[SCM] Samba Shared Repository - branch master updated

Andrew Tridgell tridge at samba.org
Fri Jan 13 23:46:02 MST 2012


The branch, master has been updated
       via  ab1f896 KCC importldif/exportldif and intersite topology
       via  aff8dad Intersite KCC flags for python
       via  11e2c84 Intersite KCC flags
      from  b8a8870 idl: add to_null property

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


- Log -----------------------------------------------------------------
commit ab1f896c5152dfd10609ac146eaaecd1bd2d5b70
Author: Dave Craft <wimberosa at gmail.com>
Date:   Wed Jan 11 08:11:35 2012 -0600

    KCC importldif/exportldif and intersite topology
    
    Add options for extracting an LDIF file from a database
    and reimporting the LDIF into a schema-less database for
    subsequent topology test/debug.  Add intersite topology
    generation with computation of ISTG and bridgehead servers
    
    Signed-off-by: Andrew Tridgell <tridge at samba.org>
    
    Autobuild-User: Andrew Tridgell <tridge at samba.org>
    Autobuild-Date: Sat Jan 14 07:45:11 CET 2012 on sn-devel-104

commit aff8dad076f803e6deb2c5b59fa3bc5cb7ca7bd7
Author: Dave Craft <wimberosa at gmail.com>
Date:   Wed Jan 11 08:10:27 2012 -0600

    Intersite KCC flags for python
    
    Add NTDSSITELINK options to dsdb class for use
    in python samba_kcc
    
    Signed-off-by: Andrew Tridgell <tridge at samba.org>

commit 11e2c8493f08214c290fec87dac18ad23de234bf
Author: Dave Craft <wimberosa at gmail.com>
Date:   Wed Jan 11 08:08:52 2012 -0600

    Intersite KCC flags
    
    NTDSSITELINK option flags added
    
    Signed-off-by: Andrew Tridgell <tridge at samba.org>

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

Summary of changes:
 libds/common/flags.h                        |    5 +
 source4/dsdb/pydsdb.c                       |    5 +
 source4/scripting/bin/samba_kcc             | 1629 ++++++++++++++++++++++++---
 source4/scripting/python/samba/kcc_utils.py | 1176 ++++++++++++++++----
 4 files changed, 2439 insertions(+), 376 deletions(-)


Changeset truncated at 500 lines:

diff --git a/libds/common/flags.h b/libds/common/flags.h
index c25a9e9..96709af 100644
--- a/libds/common/flags.h
+++ b/libds/common/flags.h
@@ -268,3 +268,8 @@
 #define NTDSCONN_OPT_DISABLE_INTERSITE_COMPRESSION	0x00000010
 #define NTDSCONN_OPT_USER_OWNED_SCHEDULE		0x00000020
 #define NTDSCONN_OPT_RODC_TOPOLOGY			0x00000040
+
+/* 7.1.1.2.2.3.3      Site Link Object options flags */
+#define NTDSSITELINK_OPT_USE_NOTIFY                     0x00000001
+#define NTDSSITELINK_OPT_TWOWAY_SYNC                    0x00000002
+#define NTDSSITELINK_OPT_DISABLE_COMPRESSION            0x00000004
diff --git a/source4/dsdb/pydsdb.c b/source4/dsdb/pydsdb.c
index f9896c0..616e169 100644
--- a/source4/dsdb/pydsdb.c
+++ b/source4/dsdb/pydsdb.c
@@ -1186,6 +1186,11 @@ void initdsdb(void)
         ADD_DSDB_FLAG(NTDSCONN_OPT_USER_OWNED_SCHEDULE);
         ADD_DSDB_FLAG(NTDSCONN_OPT_RODC_TOPOLOGY);
 
+        /* Site Link Object options */
+        ADD_DSDB_FLAG(NTDSSITELINK_OPT_USE_NOTIFY);
+        ADD_DSDB_FLAG(NTDSSITELINK_OPT_TWOWAY_SYNC);
+        ADD_DSDB_FLAG(NTDSSITELINK_OPT_DISABLE_COMPRESSION);
+
 	/* GPO policy flags */
 	ADD_DSDB_FLAG(GPLINK_OPT_DISABLE);
 	ADD_DSDB_FLAG(GPLINK_OPT_ENFORCE);
diff --git a/source4/scripting/bin/samba_kcc b/source4/scripting/bin/samba_kcc
index c17439e..583d88f 100755
--- a/source4/scripting/bin/samba_kcc
+++ b/source4/scripting/bin/samba_kcc
@@ -18,6 +18,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
+import tempfile
 import sys
 import random
 import copy
@@ -35,11 +36,15 @@ os.environ["TZ"] = "GMT"
 # Find right directory when running from source tree
 sys.path.insert(0, "bin/python")
 
-import samba, ldb
 import optparse
 import logging
 
-from samba           import getopt as options
+from samba           import (getopt as options,   \
+                             Ldb,                 \
+                             ldb,                 \
+                             dsdb,                \
+                             param,               \
+                             read_and_sub_file)
 from samba.auth      import system_session
 from samba.samdb     import SamDB
 from samba.dcerpc    import drsuapi
@@ -47,19 +52,25 @@ from samba.kcc_utils import *
 
 class KCC:
     """The Knowledge Consistency Checker class.  A container for
-       objects and methods allowing a run of the KCC.  Produces
-       a set of connections in the samdb for which the Distributed
-       Replication Service can then utilize to replicate naming
-       contexts
+    objects and methods allowing a run of the KCC.  Produces
+    a set of connections in the samdb for which the Distributed
+    Replication Service can then utilize to replicate naming
+    contexts
     """
-    def __init__(self, samdb):
+    def __init__(self):
         """Initializes the partitions class which can hold
-           our local DCs partitions or all the partitions in
-           the forest
+        our local DCs partitions or all the partitions in
+        the forest
         """
         self.part_table      = {}    # partition objects
         self.site_table      = {}
         self.transport_table = {}
+        self.sitelink_table  = {}
+
+        # Used in inter-site topology computation.  A list
+        # of connections (by NTDSConnection object) that are
+        # to be kept when pruning un-needed NTDS Connections
+        self.keep_connection_list = []
 
         self.my_dsa_dnstr  = None  # My dsa DN
         self.my_dsa        = None  # My dsa object
@@ -67,18 +78,19 @@ class KCC:
         self.my_site_dnstr = None
         self.my_site       = None
 
-        self.samdb         = samdb
+        self.samdb         = None
         return
 
     def load_all_transports(self):
         """Loads the inter-site transport objects for Sites
-           Raises an Exception on error
+
+        ::returns: Raises an Exception on error
         """
         try:
-            res = samdb.search("CN=Inter-Site Transports,CN=Sites,%s" % \
-                               samdb.get_config_basedn(),
-                               scope=ldb.SCOPE_SUBTREE,
-                               expression="(objectClass=interSiteTransport)")
+            res = self.samdb.search("CN=Inter-Site Transports,CN=Sites,%s" % \
+                                    self.samdb.get_config_basedn(),
+                                    scope=ldb.SCOPE_SUBTREE,
+                                    expression="(objectClass=interSiteTransport)")
         except ldb.LdbError, (enum, estr):
             raise Exception("Unable to find inter-site transports - (%s)" % estr)
 
@@ -91,7 +103,7 @@ class KCC:
 
             transport = Transport(dnstr)
 
-            transport.load_transport(samdb)
+            transport.load_transport(self.samdb)
 
             # Assign this transport to table
             # and index by dn
@@ -99,27 +111,96 @@ class KCC:
 
         return
 
+    def load_all_sitelinks(self):
+        """Loads the inter-site siteLink objects
+
+        ::returns: Raises an Exception on error
+        """
+        try:
+            res = self.samdb.search("CN=Inter-Site Transports,CN=Sites,%s" % \
+                                    self.samdb.get_config_basedn(),
+                                    scope=ldb.SCOPE_SUBTREE,
+                                    expression="(objectClass=siteLink)")
+        except ldb.LdbError, (enum, estr):
+            raise Exception("Unable to find inter-site siteLinks - (%s)" % estr)
+
+        for msg in res:
+            dnstr = str(msg.dn)
+
+            # already loaded
+            if dnstr in self.sitelink_table.keys():
+                continue
+
+            sitelink = SiteLink(dnstr)
+
+            sitelink.load_sitelink(self.samdb)
+
+            # Assign this siteLink to table
+            # and index by dn
+            self.sitelink_table[dnstr] = sitelink
+
+        return
+
+    def get_sitelink(self, site1_dnstr, site2_dnstr):
+        """Return the siteLink (if it exists) that connects the
+        two input site DNs
+        """
+        for sitelink in self.sitelink_table.values():
+            if sitelink.is_sitelink(site1_dnstr, site2_dnstr):
+                return sitelink
+        return None
+
     def load_my_site(self):
         """Loads the Site class for the local DSA
-           Raises an Exception on error
+
+        ::returns: Raises an Exception on error
         """
-        self.my_site_dnstr = "CN=%s,CN=Sites,%s" % (samdb.server_site_name(),
-                             samdb.get_config_basedn())
+        self.my_site_dnstr = "CN=%s,CN=Sites,%s" % \
+                             (self.samdb.server_site_name(),
+                              self.samdb.get_config_basedn())
         site = Site(self.my_site_dnstr)
-        site.load_site(samdb)
+        site.load_site(self.samdb)
 
         self.site_table[self.my_site_dnstr] = site
         self.my_site = site
         return
 
+    def load_all_sites(self):
+        """Discover all sites and instantiate and load each
+        NTDS Site settings.
+
+        ::returns: Raises an Exception on error
+        """
+        try:
+            res = self.samdb.search("CN=Sites,%s" %
+                                    self.samdb.get_config_basedn(),
+                                    scope=ldb.SCOPE_SUBTREE,
+                                    expression="(objectClass=site)")
+        except ldb.LdbError, (enum, estr):
+            raise Exception("Unable to find sites - (%s)" % estr)
+
+        for msg in res:
+            sitestr = str(msg.dn)
+
+            # already loaded
+            if sitestr in self.site_table.keys():
+                continue
+
+            site = Site(sitestr)
+            site.load_site(self.samdb)
+
+            self.site_table[sitestr] = site
+            return
+
     def load_my_dsa(self):
         """Discover my nTDSDSA dn thru the rootDSE entry
-           Raises an Exception on error.
+
+        ::returns: Raises an Exception on error.
         """
         dn = ldb.Dn(self.samdb, "")
         try:
-            res = samdb.search(base=dn, scope=ldb.SCOPE_BASE,
-                               attrs=["dsServiceName"])
+            res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE,
+                                    attrs=["dsServiceName"])
         except ldb.LdbError, (enum, estr):
             raise Exception("Unable to find my nTDSDSA - (%s)" % estr)
 
@@ -130,10 +211,12 @@ class KCC:
 
     def load_all_partitions(self):
         """Discover all NCs thru the Partitions dn and
-           instantiate and load the NCs.  Each NC is inserted
-           into the part_table by partition dn string (not
-           the nCName dn string)
-           Raises an Exception on error
+        instantiate and load the NCs.
+
+        Each NC is inserted into the part_table by partition
+        dn string (not the nCName dn string)
+
+        ::returns: Raises an Exception on error
         """
         try:
             res = self.samdb.search("CN=Partitions,%s" %
@@ -157,7 +240,7 @@ class KCC:
 
     def should_be_present_test(self):
         """Enumerate all loaded partitions and DSAs in local
-           site and test if NC should be present as replica
+        site and test if NC should be present as replica
         """
         for partdn, part in self.part_table.items():
             for dsadn, dsa in self.my_site.dsa_table.items():
@@ -172,9 +255,9 @@ class KCC:
 
     def is_stale_link_connection(self, target_dsa):
         """Returns False if no tuple z exists in the kCCFailedLinks or
-           kCCFailedConnections variables such that z.UUIDDsa is the
-           objectGUID of the target dsa, z.FailureCount > 0, and
-           the current time - z.TimeFirstFailure > 2 hours.
+        kCCFailedConnections variables such that z.UUIDDsa is the
+        objectGUID of the target dsa, z.FailureCount > 0, and
+        the current time - z.TimeFirstFailure > 2 hours.
         """
         # XXX - not implemented yet
         return False
@@ -183,13 +266,147 @@ class KCC:
         # XXX - not implemented yet
         return
 
-    def remove_unneeded_ntdsconn(self):
-        # XXX - not implemented yet
+    def remove_unneeded_ntdsconn(self, all_connected):
+        """Removes unneeded NTDS Connections after computation
+        of KCC intra and inter-site topology has finished.
+        """
+        mydsa = self.my_dsa
+
+        # Loop thru connections
+        for cn_dnstr, cn_conn in mydsa.connect_table.items():
+
+            s_dnstr = cn_conn.get_from_dnstr()
+            if s_dnstr is None:
+                cn_conn.to_be_deleted = True
+                continue
+
+            # Get the source DSA no matter what site
+            s_dsa = self.get_dsa(s_dnstr)
+
+            # Check if the DSA is in our site
+            if self.my_site.same_site(s_dsa):
+                same_site = True
+            else:
+                same_site = False
+
+            # 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 cn_conn.is_generated() == False:
+                    continue
+
+                if self.my_site.is_cleanup_ntdsconn_disabled() == True:
+                    continue
+
+                # Loop thru connections looking for a duplicate that
+                # fulfills the previous criteria
+                lesser = False
+
+                for cn2_dnstr, cn2_conn in mydsa.connect_table.items():
+                    if cn2_conn is cn_conn:
+                        continue
+
+                    s2_dnstr = cn2_conn.get_from_dnstr()
+                    if s2_dnstr is None:
+                        continue
+
+                    # If the NTDS Connections has a different
+                    # fromServer field then no match
+                    if s2_dnstr != s_dnstr:
+                        continue
+
+                    lesser = (cn_conn.whenCreated < cn2_conn.whenCreated or
+                              (cn_conn.whenCreated == cn2_conn.whenCreated and
+                               cmp(cn_conn.guid, cn2_conn.guid) < 0))
+
+                    if lesser == True:
+                        break
+
+                if lesser and cn_conn.is_rodc_topology() == False:
+                    cn_conn.to_be_deleted = True
+
+            # 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
+
+                if mydsa.is_istg() == False:
+                    continue
+
+                if cn_conn.is_generated() == False:
+                    continue
+
+                if self.keep_connection(cn_conn) == True:
+                    continue
+
+                # XXX - To be implemented
+
+                if all_connected == False:
+                    continue
+
+                if cn_conn.is_rodc_topology() == False:
+                    cn_conn.to_be_deleted = True
+
+
+        if opts.readonly:
+            for dnstr, connect in mydsa.connect_table.items():
+                if connect.to_be_deleted == True:
+                    logger.info("TO BE DELETED:\n%s" % connect)
+                if connect.to_be_added == True:
+                    logger.info("TO BE ADDED:\n%s" % connect)
+
+            # Peform deletion from our tables but perform
+            # no database modification
+            mydsa.commit_connections(self.samdb, ro=True)
+        else:
+            # Commit any modified connections
+            mydsa.commit_connections(self.samdb)
+
         return
 
     def get_dsa_by_guidstr(self, guidstr):
         """Given a DSA guid string, consule all sites looking
-           for the corresponding DSA and return it.
+        for the corresponding DSA and return it.
         """
         for site in self.site_table.values():
             dsa = site.get_dsa_by_guidstr(guidstr)
@@ -199,7 +416,7 @@ class KCC:
 
     def get_dsa(self, dnstr):
         """Given a DSA dn string, consule all sites looking
-           for the corresponding DSA and return it.
+        for the corresponding DSA and return it.
         """
         for site in self.site_table.values():
             dsa = site.get_dsa(dnstr)
@@ -209,16 +426,18 @@ class KCC:
 
     def modify_repsFrom(self, n_rep, t_repsFrom, s_rep, s_dsa, cn_conn):
         """Update t_repsFrom if necessary to satisfy requirements. Such
-           updates are typically required when the IDL_DRSGetNCChanges
-           server has moved from one site to another--for example, to
-           enable compression when the server is moved from the
-           client's site to another site.
-           :param n_rep: NC replica we need
-           :param t_repsFrom: repsFrom tuple to modify
-           :param s_rep: NC replica at source DSA
-           :param s_dsa: source DSA
-           :param cn_conn: Local DSA NTDSConnection child
-           Returns (update) bit field containing which portion of the
+        updates are typically required when the IDL_DRSGetNCChanges
+        server has moved from one site to another--for example, to
+        enable compression when the server is moved from the
+        client's site to another site.
+
+        :param n_rep: NC replica we need
+        :param t_repsFrom: repsFrom tuple to modify
+        :param s_rep: NC replica at source DSA
+        :param s_dsa: source DSA
+        :param cn_conn: Local DSA NTDSConnection child
+
+        ::returns: (update) bit field containing which portion of the
            repsFrom was modified.  This bit field is suitable as input
            to IDL_DRSReplicaModify ulModifyFields element, as it consists
            of these bits:
@@ -229,7 +448,7 @@ class KCC:
         s_dnstr = s_dsa.dsa_dnstr
         update  = 0x0
 
-        if self.my_site.get_dsa(s_dnstr) is s_dsa:
+        if self.my_site.same_site(s_dsa):
             same_site = True
         else:
             same_site = False
@@ -424,7 +643,7 @@ class KCC:
                 t_repsFrom.transport_guid = x_transport.guid
 
             # See (NOTE MS-TECH INCORRECT) above
-            if x_transport.addr_attr == "dNSHostName":
+            if x_transport.address_attr == "dNSHostName":
 
                 if t_repsFrom.version == 0x1:
                     if t_repsFrom.dns_name1 is None or \
@@ -440,21 +659,21 @@ class KCC:
 
             else:
                 # MS tech specification says we retrieve the named
-                # attribute in "addr_attr" from the parent of the
-                # DSA object
+                # attribute in "transportAddressAttribute" from the parent of
+                # the DSA object
                 try:
                     pdnstr = s_dsa.get_parent_dnstr()
-                    attrs  = [ x_transport.addr_attr ]
+                    attrs  = [ x_transport.address_attr ]
 
                     res = self.samdb.search(base=pdnstr, scope=ldb.SCOPE_BASE,
                                             attrs=attrs)
                 except ldb.ldbError, (enum, estr):
                     raise Exception \
                         ("Unable to find attr (%s) for (%s) - (%s)" % \
-                         (x_transport.addr_attr, pdnstr, estr))
+                         (x_transport.address_attr, pdnstr, estr))
 
                 msg = res[0]
-                nastr = str(msg[x_transport.addr_attr][0])


-- 
Samba Shared Repository


More information about the samba-cvs mailing list