The branch, master has been updated via 4346fe6 KCC: allow --test-all-reps-from to work with --import-ldif via 8bdfb25 KCC: samba_kcc --tmpdb X won't run if X already exists via e29fba6 KCC: with --import-ldif, don't default to standard DB url via 46ac3a5 KCC: kcc.import_ldif doesn't need creds via 6f93ffa KCC: remove NTDSConnection API methods that are never used via b93205e KCC: whitespace for pep8 via 1d5bb59 KCC: fix pep8 line length in load_ip_transport() via ab63f1a KCC: Correct capitalisation of KCCError via e9f0799 KCC: raise KCCError, not Exception, in multiple places via 2638419 KCC: NTDSConnection.load_connection() requires objectGUID via 8f59362 KCC: remove debug print statements from intrasite and intersite via 8fe9992 KCC: load samdb before calling kcc.run() via 47b3334 KCC: load the object GUID with --import-ldif via 30330b4 KCC: avoid logging alarming things about exected events via ad009be KCC: shift --test-all-reps-from call to after kcc loading via a9ddca0 KCC: Simplify RNG seeding logic, dropping the default value via e442726 KCC: more debug info when --import-ldif goes badly via acd7728 KCC: default to not loading new samdb when we already have one via 76f195a KCC: fix typo in error path via 6f78ad2 KCC: better explain our confusion in colour_vertices comment via 310aa2f KCC: clarify debugging messages in bridgehead finding code via 5f60c4b KCC: keep track of IP transport for dsa.new_connection() via 059e283 KCC: set system flags for new intrasite connections via 704fd83 KCC: correctly use dsa.new_connection() system_flags argument via 4bf95b6 KCC: Use detect_failed in create_connections via 0f8f99f KCC: remove useless comments and simplify get_dsa_for_implied_replica() via 24ae662 KCC: stop --forget-intersite-links forgetting local links via eec0d11 KCC: simplify get_dsa_for_implied_replica(), using IP invariant via 5bbcbe3 KCC: Share commit wrapper between forget_ntdsconn and intrasite via 03e3522 KCC: pull apart remove_unneeded_ntdsconn(), fixing intersite via 472735f KCC: shift common is_generated() check out of branches from 6e3cb6b s4:torture: fix a comment typo.
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 4346fe6a0259e326bd5254a9d192f0807b27331e Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Tue Jun 23 16:38:29 2015 +1200 KCC: allow --test-all-reps-from to work with --import-ldif The ldif files lack information that a normal database has, which means the ldif import function has to use some trickery to set the local DSA. Once the local DSA is thus set, the fake database is a bit useless from the point of view of other DSAs. We get around this by re-importing it each time. This is doing something slightly different than the normal samdb --test-all-reps-from, in that the changes are not preserved between each DSA's run. With the samdb database (unless using --readonly), the later DSA's will see changes the early ones made. The ordering is arbitrary. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> Autobuild-User(master): Andrew Bartlett <abart...@samba.org> Autobuild-Date(master): Thu Oct 29 08:11:54 CET 2015 on sn-devel-104 commit 8bdfb256d6c4fdeaaa118fc6da841daebc1c377d Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Tue Jun 23 16:38:29 2015 +1200 KCC: samba_kcc --tmpdb X won't run if X already exists Part of an ongoing safety campaign, making it harder to overwrite your valuable things while keeping it easy enough to test crazy schemes. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit e29fba640b7d543f1e7177aa9357c82f590b6b07 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Tue Jun 23 16:38:29 2015 +1200 KCC: with --import-ldif, don't default to standard DB url Before samba_kcc would always assume `-H /usr/local/whatever`, and this interacted badly with the likes of `--test-all-reps-from` and `--forget-intersite-links`. When I say badly, I mean it crashed because the file is absent on my dev machine. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 46ac3a5308dfc5d03173bbae03734ba327f0e570 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Tue Jun 23 16:38:29 2015 +1200 KCC: kcc.import_ldif doesn't need creds Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 6f93ffaf0c446cd72478317636c0dcd7e0f4f4b8 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Tue Jun 23 16:38:29 2015 +1200 KCC: remove NTDSConnection API methods that are never used These are not used, and using them would not be considered Pythonic. The flags they alter are always changed directly. The similar set_modified() method IS used. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit b93205ebe4cb54175642ee60e18354f7bfb4c0fd Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Tue Jun 23 16:38:29 2015 +1200 KCC: whitespace for pep8 Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 1d5bb5996e7df31aac746375a5cc24a91ee52d7e Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Tue Jun 23 16:38:29 2015 +1200 KCC: fix pep8 line length in load_ip_transport() You are right to sigh about this one. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit ab63f1a9839c286cf7f345cc62207d9b95a5af62 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Mon Jun 22 16:38:29 2015 +1200 KCC: Correct capitalisation of KCCError previously we had "raise KccError", which of course would raise a NameError. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit e9f0799a18955e9fec1478a6019a333f588b26cc Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Mon Jun 22 16:38:29 2015 +1200 KCC: raise KCCError, not Exception, in multiple places "except Exception" lines will still catch them, but more fine-grained control is possible. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 26384192d56d765a8ea4667fac7c9b7ad2e3d415 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Mon Jun 22 16:38:29 2015 +1200 KCC: NTDSConnection.load_connection() requires objectGUID If there is no GUID, that is an error, so we raise an exception instead of stepping around it. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 8f5936261f221f6a83fc294e308160d9fb9562e3 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Mon Jun 22 16:38:29 2015 +1200 KCC: remove debug print statements from intrasite and intersite Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 8fe9992cffed82e9e26ebe8185f372c8a1dfb3a9 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Mon Jun 22 16:38:29 2015 +1200 KCC: load samdb before calling kcc.run() kcc.run() is a mega-function that does nearly everything, including loading the database. The --list-valid-dsas and --test-all-reps-from tasks also want to load the database, but not do all that other run() stuff, so it makes sense to pull it out. When the samdb has not been loaded, run() will still load it -- this avoids having to change all the tests. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 47b3334f48f21118ba1f61e841eb95920f384ee4 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Mon Jun 22 16:38:29 2015 +1200 KCC: load the object GUID with --import-ldif Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 30330b4df8e1542a2c9fd2ca256cb58029b6cbf4 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Mon Jun 22 16:38:29 2015 +1200 KCC: avoid logging alarming things about exected events Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit ad009be3297ec9343fd07ea86a197dc11ab8890f Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 17 16:38:29 2015 +1200 KCC: shift --test-all-reps-from call to after kcc loading This is in an effort to allow --test-all-reps-from to work with --import-ldif (though so far it doesn't for other reasons). Rather than replicate all the ldif loading logic within test_all_reps_from, we just wait delay the test_all_reps_from() call. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit a9ddca042c51de5c95327f41e3a31c178f5ab85b Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 17 16:38:29 2015 +1200 KCC: Simplify RNG seeding logic, dropping the default value There is no particular justification for the previous default, other than being deterministic makes testing more reliable. The algorithms using randomness do not assume determinism. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit e442726c3d59bf861058ac81735653d9f91610a2 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 17 16:38:29 2015 +1200 KCC: more debug info when --import-ldif goes badly Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit acd77283ccf3253bb7d5d048465bbf8e77a89982 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 17 16:38:29 2015 +1200 KCC: default to not loading new samdb when we already have one This should make things simpler in the --import-ldif case. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 76f195a2792d0c4cd86a337881d1ce01194113af Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 17 16:38:29 2015 +1200 KCC: fix typo in error path Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 6f78ad24506928f48f5a26bf87f3d4de460f0cde Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 10 16:38:29 2015 +1200 KCC: better explain our confusion in colour_vertices comment Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 310aa2f3408800498876768091f3533e3332b75b Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 10 16:38:29 2015 +1200 KCC: clarify debugging messages in bridgehead finding code Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 5f60c4bf33cd94c84cad0ba5768474435a515af0 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 10 16:38:29 2015 +1200 KCC: keep track of IP transport for dsa.new_connection() Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 059e2838c8a61ffbb0865e665694c02bb531758b Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 10 16:38:29 2015 +1200 KCC: set system flags for new intrasite connections These flags are mandatory for intrasite connections. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 704fd83bcf5bba3bf5e67ea8060aff148aacea32 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 10 16:38:29 2015 +1200 KCC: correctly use dsa.new_connection() system_flags argument The dsa.system_flags attribute is important and gets saved in the database, but was never getting altered because we were setting dsa.flags instead. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 4bf95b6b32dfc8ecc0aac92971e173b826e2d4ac Author: Garming Sam <garm...@catalyst.net.nz> Date: Fri Jun 26 16:38:29 2015 +1200 KCC: Use detect_failed in create_connections Without this, dead DCs were treated as live, and could be used in the tree. If they're in the tree they can split the network. Signed-off-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 0f8f99f6af2785d6774ca9436b6eef2078a246df Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Thu Jun 25 16:38:29 2015 +1200 KCC: remove useless comments and simplify get_dsa_for_implied_replica() These comments are a close reflection (or possibly copy/paste) of the spec, but our code here no longer resembles the spec. We end up just glazing over when we see comments and losing track of the flow of code. If you want the spec just look at the spec. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 24ae662eaee03a0e5d1046acf6882bc6842f518a Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Thu Jun 25 16:38:29 2015 +1200 KCC: stop --forget-intersite-links forgetting local links It will still forget intrasite links on other sites, but that in theory should not matter. It will still break your network, and is only useful for debugging. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit eec0d119ac755b72f8e881728608a849ad12b66b Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Thu Jun 25 16:38:29 2015 +1200 KCC: simplify get_dsa_for_implied_replica(), using IP invariant We only do IP transports. Therfore the long list of alternatives... (not n_rep.is_domain() or n_rep.is_partial() or cn_conn.transport_dnstr is None or cn_conn.transport_dnstr.find("CN=IP") == 0) that ends with the equivalant of "is this IP?" always evaluates to True. If we leave it there it will confuse people for ever. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 5bbcbe380b8b5cb7a9f479e585f46040f2d99ad5 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Thu Jun 25 16:38:29 2015 +1200 KCC: Share commit wrapper between forget_ntdsconn and intrasite The wrapper is only to create DEBUG output in read-only mode -- normally it amounts to `dsa.commit_connections(self.samdb)`. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 03e352268a80a4671b50855a977a655b095ddf18 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Thu Jun 25 16:38:29 2015 +1200 KCC: pull apart remove_unneeded_ntdsconn(), fixing intersite The confusing big mess was hiding bugs. Firstly, intersite links on non-intersite-topology-generators were not getting looked at. Secondly, the logic around superseding intersite links was missing. Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 472735f26c3bc67d4a04d08038d1f63c1b275986 Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Date: Wed Jun 17 15:11:20 2015 +1200 KCC: shift common is_generated() check out of branches Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> ----------------------------------------------------------------------- Summary of changes: python/samba/kcc/__init__.py | 372 ++++++++++++--------------- python/samba/kcc/kcc_utils.py | 105 ++++---- python/samba/kcc/ldif_import_export.py | 2 +- python/samba/tests/kcc/ldif_import_export.py | 6 +- source4/scripting/bin/samba_kcc | 74 ++++-- 5 files changed, 274 insertions(+), 285 deletions(-) Changeset truncated at 500 lines: diff --git a/python/samba/kcc/__init__.py b/python/samba/kcc/__init__.py index 46a25ce..c3e92b7 100644 --- a/python/samba/kcc/__init__.py +++ b/python/samba/kcc/__init__.py @@ -165,11 +165,12 @@ class KCC(object): if transport.name == 'IP': self.ip_transport = transport elif transport.name == 'SMTP': - logger.info("Samba KCC is ignoring the obsolete SMTP transport.") + logger.debug("Samba KCC is ignoring the obsolete " + "SMTP transport.") else: - logger.warning("Samba KCC does not support the transport called %r." - % (transport.name,)) + logger.warning("Samba KCC does not support the transport " + "called %r." % (transport.name,)) if self.ip_transport is None: raise KCCError("there doesn't seem to be an IP transport") @@ -261,14 +262,15 @@ class KCC(object): :return: None :raise: KCCError if DSA can't be found """ - dn = ldb.Dn(self.samdb, "<GUID=%s>" % self.samdb.get_ntds_GUID()) + dn_query = "<GUID=%s>" % self.samdb.get_ntds_GUID() + dn = ldb.Dn(self.samdb, dn_query) try: res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"]) except ldb.LdbError, (enum, estr): - logger.warning("Search for %s failed: %s. This typically happens" - " in --importldif mode due to lack of module" - " support.", dn, estr) + DEBUG_FN("Search for dn '%s' [from %s] failed: %s. " + "This typically happens in --importldif mode due " + "to lack of module support." % (dn, dn_query, estr)) try: # We work around the failure above by looking at the # dsServiceName that was put in the fake rootdse by @@ -305,7 +307,7 @@ class KCC(object): " it must be RODC.\n" "Let's add it, because my_dsa is special!" "\n(likewise for self.dsa_by_guid)" % - self.my_dsas_dnstr) + self.my_dsa_dnstr) self.dsa_by_dnstr[self.my_dsa_dnstr] = self.my_dsa self.dsa_by_guid[str(self.my_dsa.dsa_guid)] = self.my_dsa @@ -432,19 +434,17 @@ class KCC(object): # that became active during this run. pass - def remove_unneeded_ntdsconn(self, all_connected): - """Remove unneeded NTDS Connections once topology is calculated + def _ensure_connections_are_loaded(self, connections): + """Load or fake-load NTDSConnections lacking GUIDs - Based on MS-ADTS 6.2.2.4 Removing Unnecessary Connections + New connections don't have GUIDs and created times which are + needed for sorting. If we're in read-only mode, we make fake + GUIDs, otherwise we ask SamDB to do it for us. - :param all_connected: indicates whether all sites are connected + :param connections: an iterable of NTDSConnection objects. :return: None """ - mydsa = self.my_dsa - - # New connections won't have GUIDs which are needed for - # sorting. Add them. - for cn_conn in mydsa.connect_table.values(): + for cn_conn in connections: if cn_conn.guid is None: if self.readonly: cn_conn.guid = misc.GUID(str(uuid.uuid4())) @@ -452,135 +452,139 @@ class KCC(object): else: cn_conn.load_connection(self.samdb) - for cn_conn in mydsa.connect_table.values(): + def _mark_broken_ntdsconn(self): + """Find NTDS Connections that lack a remote + + I'm not sure how they appear. Let's be rid of them by marking + them with the to_be_deleted attribute. + :return: None + """ + for cn_conn in self.my_dsa.connect_table.values(): s_dnstr = cn_conn.get_from_dnstr() if s_dnstr is None: + DEBUG_FN("%s has phantom connection %s" % (self.my_dsa, + cn_conn)) cn_conn.to_be_deleted = True - continue - #XXX should an RODC be regarded as same site - same_site = s_dnstr in self.my_site.dsa_table - - # Given an nTDSConnection object cn, if the DC with the - # nTDSDSA object dc that is the parent object of cn and - # the DC with the nTDSDA object referenced by cn!fromServer - # are in the same site, the KCC on dc deletes cn if all of - # the following are true: - # - # Bit NTDSCONN_OPT_IS_GENERATED is clear in cn!options. - # - # No site settings object s exists for the local DC's site, or - # bit NTDSSETTINGS_OPT_IS_TOPL_CLEANUP_DISABLED is clear in - # s!options. - # - # Another nTDSConnection object cn2 exists such that cn and - # cn2 have the same parent object, cn!fromServer = cn2!fromServer, - # and either - # - # cn!whenCreated < cn2!whenCreated - # - # cn!whenCreated = cn2!whenCreated and - # cn!objectGUID < cn2!objectGUID - # - # Bit NTDSCONN_OPT_RODC_TOPOLOGY is clear in cn!options - if same_site: - if not cn_conn.is_generated(): - continue - - if self.my_site.is_cleanup_ntdsconn_disabled(): - continue - - # Loop thru connections looking for a duplicate that - # fulfills the previous criteria - lesser = False - packed_guid = ndr_pack(cn_conn.guid) - for cn2_conn in mydsa.connect_table.values(): - if cn2_conn is cn_conn: - continue + def _mark_unneeded_local_ntdsconn(self): + """Find unneeded intrasite NTDS Connections for removal - s2_dnstr = cn2_conn.get_from_dnstr() + Based on MS-ADTS 6.2.2.4 Removing Unnecessary Connections. + Every DC removes its own unnecessary intrasite connections. + This function tags them with the to_be_deleted attribute. - # If the NTDS Connections has a different - # fromServer field then no match - if s2_dnstr != s_dnstr: - continue + :return: None + """ + # XXX should an RODC be regarded as same site? It isn't part + # of the intrasite ring. - lesser = (cn_conn.whenCreated < cn2_conn.whenCreated or - (cn_conn.whenCreated == cn2_conn.whenCreated and - packed_guid < ndr_pack(cn2_conn.guid))) + if self.my_site.is_cleanup_ntdsconn_disabled(): + DEBUG_FN("not doing ntdsconn cleanup for site %s, " + "because it is disabled" % self.my_site) + return - if lesser: - break + mydsa = self.my_dsa - if lesser and not cn_conn.is_rodc_topology(): - cn_conn.to_be_deleted = True + self._ensure_connections_are_loaded(mydsa.connect_table.values()) - # Given an nTDSConnection object cn, if the DC with the nTDSDSA - # object dc that is the parent object of cn and the DC with - # the nTDSDSA object referenced by cn!fromServer are in - # different sites, a KCC acting as an ISTG in dc's site - # deletes cn if all of the following are true: - # - # Bit NTDSCONN_OPT_IS_GENERATED is clear in cn!options. - # - # cn!fromServer references an nTDSDSA object for a DC - # in a site other than the local DC's site. - # - # The keepConnections sequence returned by - # CreateIntersiteConnections() does not contain - # cn!objectGUID, or cn is "superseded by" (see below) - # another nTDSConnection cn2 and keepConnections - # contains cn2!objectGUID. - # - # The return value of CreateIntersiteConnections() - # was true. - # - # Bit NTDSCONN_OPT_RODC_TOPOLOGY is clear in - # cn!options - # - else: # different site + local_connections = [] - if not mydsa.is_istg(): - continue + for cn_conn in mydsa.connect_table.values(): + s_dnstr = cn_conn.get_from_dnstr() + if s_dnstr in self.my_site.dsa_table: + removable = not (cn_conn.is_generated() or + cn_conn.is_rodc_topology()) + packed_guid = ndr_pack(cn_conn.guid) + local_connections.append((cn_conn, s_dnstr, + packed_guid, removable)) + + for a, b in itertools.permutations(local_connections, 2): + cn_conn, s_dnstr, packed_guid, removable = a + cn_conn2, s_dnstr2, packed_guid2, removable2 = b + if (removable and + s_dnstr == s_dnstr2 and + cn_conn.whenCreated < cn_conn2.whenCreated or + (cn_conn.whenCreated == cn_conn2.whenCreated and + packed_guid < packed_guid2)): + cn_conn.to_be_deleted = True - if not cn_conn.is_generated(): - continue + def _mark_unneeded_intersite_ntdsconn(self): + """find unneeded intersite NTDS Connections for removal - # TODO - # We are directly using this connection in intersite or - # we are using a connection which can supersede this one. - # - # MS-ADTS 6.2.2.4 - Removing Unnecessary Connections does not - # appear to be correct. - # - # 1. cn!fromServer and cn!parent appear inconsistent with - # no cn2 - # 2. The repsFrom do not imply each other - # - if cn_conn in self.kept_connections: # and not_superceded: - continue + Based on MS-ADTS 6.2.2.4 Removing Unnecessary Connections. The + intersite topology generator removes links for all DCs in its + site. Here we just tag them with the to_be_deleted attribute. - # This is the result of create_intersite_connections - if not all_connected: - continue + :return: None + """ + # Find the intersite connections + local_dsas = self.my_site.dsa_table + connections_and_dsas = [] + for dsa in local_dsas.values(): + for cn in dsa.connect_table.values(): + s_dnstr = cn.get_from_dnstr() + if s_dnstr not in local_dsas: + from_dsa = self.get_dsa(s_dnstr) + connections_and_dsas.append((cn, dsa, from_dsa)) + + self._ensure_connections_are_loaded(x[0] for x in connections_and_dsas) + for cn, to_dsa, from_dsa in connections_and_dsas: + if not cn.is_generated() or cn.is_rodc_topology(): + continue - if not cn_conn.is_rodc_topology(): - cn_conn.to_be_deleted = True + # If the connection is in the kept_connections list, we + # only remove it if an endpoint seems down. + if (cn in self.kept_connections and + not (self.is_bridgehead_failed(to_dsa, True) or + self.is_bridgehead_failed(from_dsa, True))): + continue - if mydsa.is_ro() or self.readonly: - for connect in mydsa.connect_table.values(): + # this one is broken and might be superseded by another. + # But which other? Let's just say another link to the same + # site can supersede. + from_dnstr = from_dsa.dsa_dnstr + for site in self.site_table.values(): + if from_dnstr in site.rw_dsa_table: + for cn2, to_dsa2, from_dsa2 in connections_and_dsas: + if (cn is not cn2 and + from_dsa2 in site.rw_dsa_table): + cn.to_be_deleted = True + + def _commit_changes(self, dsa): + if dsa.is_ro() or self.readonly: + for connect in dsa.connect_table.values(): if connect.to_be_deleted: - DEBUG_FN("TO BE DELETED:\n%s" % connect) + logger.info("TO BE DELETED:\n%s" % connect) if connect.to_be_added: - DEBUG_FN("TO BE ADDED:\n%s" % connect) + logger.info("TO BE ADDED:\n%s" % connect) + if connect.to_be_modified: + logger.info("TO BE MODIFIED:\n%s" % connect) # Peform deletion from our tables but perform # no database modification - mydsa.commit_connections(self.samdb, ro=True) + dsa.commit_connections(self.samdb, ro=True) else: # Commit any modified connections - mydsa.commit_connections(self.samdb) + dsa.commit_connections(self.samdb) + + def remove_unneeded_ntdsconn(self, all_connected): + """Remove unneeded NTDS Connections once topology is calculated + + Based on MS-ADTS 6.2.2.4 Removing Unnecessary Connections + + :param all_connected: indicates whether all sites are connected + :return: None + """ + self._mark_broken_ntdsconn() + self._mark_unneeded_local_ntdsconn() + # if we are not the istg, we're done! + # if we are the istg, but all_connected is False, we also do nothing. + if self.my_dsa.is_istg() and all_connected: + self._mark_unneeded_intersite_ntdsconn() + + for dsa in self.my_site.dsa_table.values(): + self._commit_changes(dsa) def modify_repsFrom(self, n_rep, t_repsFrom, s_rep, s_dsa, cn_conn): """Update an repsFrom object if required. @@ -797,14 +801,12 @@ class KCC(object): :param cn_conn: NTDS Connection :return: source DSA or None """ - #XXX different conditions for "implies" than MS-ADTS 6.2.2 + # XXX different conditions for "implies" than MS-ADTS 6.2.2 + # preamble. - # NTDS Connection must satisfy all the following criteria - # to imply a repsFrom tuple is needed: - # - # cn!enabledConnection = true. - # cn!options does not contain NTDSCONN_OPT_RODC_TOPOLOGY. - # cn!fromServer references an nTDSDSA object. + # It boils down to: we want an enabled, non-FRS connections to + # a valid remote DSA with a non-RO replica corresponding to + # n_rep. if not cn_conn.is_enabled() or cn_conn.is_rodc_topology(): return None @@ -816,39 +818,11 @@ class KCC(object): if s_dsa is None: return None - # To imply a repsFrom tuple is needed, each of these - # must be True: - # - # An NC replica of the NC "is present" on the DC to - # which the nTDSDSA object referenced by cn!fromServer - # corresponds. - # - # An NC replica of the NC "should be present" on - # the local DC s_rep = s_dsa.get_current_replica(n_rep.nc_dnstr) - if s_rep is None or not s_rep.is_present(): - return None - - # To imply a repsFrom tuple is needed, each of these - # must be True: - # - # The NC replica on the DC referenced by cn!fromServer is - # a writable replica or the NC replica that "should be - # present" on the local DC is a partial replica. - # - # The NC is not a domain NC, the NC replica that - # "should be present" on the local DC is a partial - # replica, cn!transportType has no value, or - # cn!transportType has an RDN of CN=IP. - # - implied = (not s_rep.is_ro() or n_rep.is_partial()) and \ - (not n_rep.is_domain() or - n_rep.is_partial() or - cn_conn.transport_dnstr is None or - cn_conn.transport_dnstr.find("CN=IP") == 0) - - if implied: + if (s_rep is not None and + s_rep.is_present() and + (not s_rep.is_ro() or n_rep.is_partial())): return s_dsa return None @@ -1106,14 +1080,14 @@ class KCC(object): bhs = self.get_all_bridgeheads(site, part, transport, partial_ok, detect_failed) - if len(bhs) == 0: - debug.DEBUG_MAGENTA("get_bridgehead:\n\tsitedn=%s\n\tbhdn=None" % + if not bhs: + debug.DEBUG_MAGENTA("get_bridgehead FAILED:\nsitedn = %s" % site.site_dnstr) return None - else: - debug.DEBUG_GREEN("get_bridgehead:\n\tsitedn=%s\n\tbhdn=%s" % - (site.site_dnstr, bhs[0].dsa_dnstr)) - return bhs[0] + + debug.DEBUG_GREEN("get_bridgehead:\n\tsitedn = %s\n\tbhdn = %s" % + (site.site_dnstr, bhs[0].dsa_dnstr)) + return bhs[0] def get_all_bridgeheads(self, site, part, transport, partial_ok, detect_failed): @@ -1141,7 +1115,6 @@ class KCC(object): "non-IP transport! %r" % (transport.name,)) - DEBUG_FN("get_all_bridgeheads") DEBUG_FN(site.rw_dsa_table) for dsa in site.rw_dsa_table.values(): @@ -1189,7 +1162,7 @@ class KCC(object): DEBUG("bridgehead is failed") continue - DEBUG_FN("get_all_bridgeheads: dsadn=%s" % dsa.dsa_dnstr) + DEBUG_FN("found a bridgehead: %s" % dsa.dsa_dnstr) bhs.append(dsa) # IF bit NTDSSETTINGS_OPT_IS_RAND_BH_SELECTION_DISABLED is set in @@ -1490,7 +1463,10 @@ class KCC(object): # cn!options = opt, cn!transportType is a reference to t, # cn!fromServer is a reference to rbh, and cn!schedule = sch DEBUG_FN("new connection, KCC dsa: %s" % self.my_dsa.dsa_dnstr) - cn = lbh.new_connection(opt, 0, transport, + system_flags = (dsdb.SYSTEM_FLAG_CONFIG_ALLOW_RENAME | + dsdb.SYSTEM_FLAG_CONFIG_ALLOW_MOVE) + + cn = lbh.new_connection(opt, system_flags, transport, rbh.dsa_dnstr, link_sched) # Display any added connection @@ -1525,7 +1501,7 @@ class KCC(object): # here, but using vertex seems to make more sense. That is, # the docs want this: # - #bh = self.get_bridgehead(vertex.site, vertex.part, transport, + #bh = self.get_bridgehead(local_vertex.site, vertex.part, transport, # local_vertex.is_black(), detect_failed) # # TODO WHY????? @@ -1596,7 +1572,7 @@ class KCC(object): for v in graph.vertices: v.color_vertex() - if self.add_transports(v, my_vertex, graph, False): + if self.add_transports(v, my_vertex, graph, detect_failed): found_failed = True # No NC replicas for this NC in the site of the local DC, @@ -2159,7 +2135,6 @@ class KCC(object): if not self.get_dsa(x).is_ro()) rw_dot_edges = [(a, b) for a, b in dot_edges if a in rw_dot_vertices and b in rw_dot_vertices] - print rw_dot_edges, rw_dot_vertices rw_verify_properties = ('connected', 'directed_double_ring_or_small') verify_and_dot('intrasite_rw_pre_ntdscon', rw_dot_edges, @@ -2230,7 +2205,7 @@ class KCC(object): # points to us that satisfies the KCC criteria if tnode.dsa_dnstr == dc_local.dsa_dnstr: - tnode.add_connections_from_edges(dc_local) + tnode.add_connections_from_edges(dc_local, self.ip_transport) if self.verify or do_dot_files: dot_edges = [] @@ -2255,7 +2230,6 @@ class KCC(object): if not self.get_dsa(x).is_ro()) rw_dot_edges = [(a, b) for a, b in dot_edges if a in rw_dot_vertices and b in rw_dot_vertices] - print rw_dot_edges, rw_dot_vertices rw_verify_properties = ('connected', 'directed_double_ring_or_small') verify_and_dot('intrasite_rw_post_ntdscon', rw_dot_edges, @@ -2346,20 +2320,7 @@ class KCC(object): self.construct_intrasite_graph(mysite, mydsa, part, True, False) # don't detect stale - if self.readonly: - # Display any to be added or modified repsFrom - for connect in mydsa.connect_table.values(): - if connect.to_be_deleted: - logger.info("TO BE DELETED:\n%s" % connect) - if connect.to_be_modified: - logger.info("TO BE MODIFIED:\n%s" % connect) - if connect.to_be_added: - debug.DEBUG_GREEN("TO BE ADDED:\n%s" % connect) - - mydsa.commit_connections(self.samdb, ro=True) - else: - # Commit any newly created connections to the samdb - mydsa.commit_connections(self.samdb) + self._commit_changes(mydsa) def list_dsas(self): """Compile a comprehensive list of DSA DNs @@ -2385,16 +2346,26 @@ class KCC(object): -- Samba Shared Repository