kcc: Add corresponding methods for repsTo
authorGarming Sam <garming@catalyst.net.nz>
Fri, 22 Jul 2016 02:14:20 +0000 (14:14 +1200)
committerGarming Sam <garming@samba.org>
Mon, 25 Jul 2016 23:22:16 +0000 (01:22 +0200)
Signed-off-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/kcc/kcc_utils.py

index e62451963db26cb20b88bdbe44adb692d62a3789..1e5586a2c4199cef55359c001232f7cc47e63c48 100644 (file)
@@ -196,6 +196,9 @@ class NCReplica(NamingContext):
         # RepsFromTo tuples
         self.rep_repsFrom = []
 
+        # RepsFromTo tuples
+        self.rep_repsTo = []
+
         # The (is present) test is a combination of being
         # enumerated in (hasMasterNCs or msDS-hasFullReplicaNCs or
         # hasPartialReplicaNCs) as well as its replica flags found
@@ -220,6 +223,9 @@ class NCReplica(NamingContext):
         for rep in self.rep_repsFrom:
             text = text + "\n%s" % rep
 
+        for rep in self.rep_repsTo:
+            text = text + "\n%s" % rep
+
         return "%s\n%s" % (NamingContext.__str__(self), text)
 
     def set_instantiated_flags(self, flags=None):
@@ -451,6 +457,95 @@ class NCReplica(NamingContext):
             return True
         return False
 
+    def load_repsTo(self, samdb):
+        """Given an NC replica which has been discovered thru the nTDSDSA
+        database object, load the repsTo attribute for the local replica.
+        held by my dsa.  The repsTo attribute is not replicated so this
+        attribute is relative only to the local DSA that the samdb exists on
+
+        This is responsible for push replication, not scheduled pull
+        replication. Not to be confused for repsFrom.
+        """
+        try:
+            res = samdb.search(base=self.nc_dnstr, scope=ldb.SCOPE_BASE,
+                               attrs=["repsTo"])
+
+        except ldb.LdbError, (enum, estr):
+            raise KCCError("Unable to find NC for (%s) - (%s)" %
+                           (self.nc_dnstr, estr))
+
+        msg = res[0]
+
+        # Possibly no repsTo if this is a singleton DC
+        if "repsTo" in msg:
+            for value in msg["repsTo"]:
+                rep = RepsFromTo(self.nc_dnstr,
+                                 ndr_unpack(drsblobs.repsFromToBlob, value))
+                self.rep_repsTo.append(rep)
+
+    def commit_repsTo(self, samdb, ro=False):
+        """Commit repsTo to the database"""
+
+        # XXX - This is not truly correct according to the MS-TECH
+        #       docs.  To commit a repsTo we should be using RPCs
+        #       IDL_DRSReplicaAdd, IDL_DRSReplicaModify, and
+        #       IDL_DRSReplicaDel to affect a repsTo change.
+        #
+        #       Those RPCs are missing in samba, so I'll have to
+        #       implement them to get this to more accurately
+        #       reflect the reference docs.  As of right now this
+        #       commit to the database will work as its what the
+        #       older KCC also did
+        modify = False
+        newreps = []
+        delreps = []
+
+        for repsTo in self.rep_repsTo:
+
+            # Leave out any to be deleted from
+            # replacement list.  Build a list
+            # of to be deleted reps which we will
+            # remove from rep_repsTo list below
+            if repsTo.to_be_deleted:
+                delreps.append(repsTo)
+                modify = True
+                continue
+
+            if repsTo.is_modified():
+                repsTo.set_unmodified()
+                modify = True
+
+            # current (unmodified) elements also get
+            # appended here but no changes will occur
+            # unless something is "to be modified" or
+            # "to be deleted"
+            newreps.append(ndr_pack(repsTo.ndr_blob))
+
+        # Now delete these from our list of rep_repsTo
+        for repsTo in delreps:
+            self.rep_repsTo.remove(repsTo)
+        delreps = []
+
+        # Nothing to do if no reps have been modified or
+        # need to be deleted or input option has informed
+        # us to be "readonly" (ro).  Leave database
+        # record "as is"
+        if not modify or ro:
+            return
+
+        m = ldb.Message()
+        m.dn = ldb.Dn(samdb, self.nc_dnstr)
+
+        m["repsTo"] = \
+            ldb.MessageElement(newreps, ldb.FLAG_MOD_REPLACE, "repsTo")
+
+        try:
+            samdb.modify(m)
+
+        except ldb.LdbError, estr:
+            raise KCCError("Could not set repsTo for (%s) - (%s)" %
+                           (self.nc_dnstr, estr))
+
 
 class DirectoryServiceAgent(object):