s4-upgradeprovision: introduce invocation id in lastprovisionUSNs
authorMatthieu Patou <mat@matws.net>
Mon, 13 Jun 2011 13:39:06 +0000 (17:39 +0400)
committerMatthieu Patou <mat@samba.org>
Sun, 19 Jun 2011 21:21:08 +0000 (23:21 +0200)
source4/scripting/bin/upgradeprovision
source4/scripting/python/samba/provision/__init__.py

index a9dffc0ab58bedf13dfdd747745b2a548c342a93..7f11e404ab0fc0573adc6e311bbf82463c890c1e 100755 (executable)
@@ -902,10 +902,22 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current,
 
         attrUSN = None
         if hash_attr_usn.get(att):
-            attrUSN = hash_attr_usn.get(att)
+            [attrUSN, attInvId] = hash_attr_usn.get(att)
+
+        if attrUSN is None:
+            # If it's a replicated attribute and we don't have any USN
+            # information about it. It means that we never saw it before
+            # so let's add it !
+            # If it is a replicated attribute but we are not master on it
+            # (ie. not initially added in the provision we masterize).
+            # attrUSN will be -1
+            if isReplicated(att):
+                continue
+            elif att in hashAttrNotCopied.keys():
+                delta.remove(att)
+            else:
+                continue
 
-        if att == "forceLogoff" and attrUSN is None:
-            continue
         if attrUSN is None:
             delta.remove(att)
             continue
@@ -956,7 +968,7 @@ def checkKeepAttributeWithMetadata(delta, att, message, reference, current,
 
     return delta
 
-def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
+def update_present(ref_samdb, samdb, basedn, listPresent, usns):
     """ This function updates the object that are already present in the
         provision
 
@@ -966,8 +978,8 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
                    (ie. DC=foo, DC=bar)
     :param listPresent: A list of object that is present in the provision
     :param usns: A list of USN range modified by previous provision and
-                 upgradeprovision
-    :param invocationid: The value of the invocationid for the current DC"""
+                 upgradeprovision grouped by invocation ID
+    """
 
     # This hash is meant to speedup lookup of attribute name from an oid,
     # it's for the replPropertyMetaData handling
@@ -1026,10 +1038,10 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid):
                 # We put in this hash only modification
                 # made on the current host
                 att = hash_oid_name[samdb.get_oid_from_attid(o.attid)]
-                if str(o.originating_invocation_id) == str(invocationid):
-                # Note we could just use 1 here
-                    hash_attr_usn[att] = o.originating_usn
+                if str(o.originating_invocation_id) in usns.keys():
+                    hash_attr_usn[att] = [o.originating_usn, str(o.originating_invocation_id)]
                 else:
+                    hash_attr_usn[att] = [-1, None]
 
         if usns is not None:
             delta = checkKeepAttributeWithMetadata(delta, att, message, reference,
@@ -1160,7 +1172,7 @@ def update_partition(ref_samdb, samdb, basedn, names, schema, provisionUSNs, pre
         message(SIMPLE, "Schema reloaded!")
 
         changed = update_present(ref_samdb, samdb, basedn, listPresent,
-                                    provisionUSNs, names.invocation)
+                                    provisionUSNs)
         message(SIMPLE, "There are %d changed objects" % (changed))
         return 1
 
@@ -1665,9 +1677,19 @@ if __name__ == '__main__':
         # 4)
         lastProvisionUSNs = get_last_provision_usn(ldbs.sam)
         if lastProvisionUSNs is not None:
+            v = 0
+            for k in lastProvisionUSNs.keys():
+                for r in lastProvisionUSNs[k]:
+                    v = v + 1
+
             message(CHANGE,
-                "Find a last provision USN, %d range(s)" % len(lastProvisionUSNs))
+                "Find last provision USN, %d invocation(s) for a total of %d ranges" % \
+                            (len(lastProvisionUSNs.keys()), v /2 ))
 
+            if lastProvisionUSNs.get("default") != None:
+                message(CHANGE, "Old style for usn ranges used")
+                lastProvisionUSNs[str(names.invocation)] = lastProvisionUSNs["default"]
+                del lastProvisionUSNs["default"]
         # Objects will be created with the admin session
         # (not anymore system session)
         adm_session = admin_session(lp, str(names.domainsid))
@@ -1853,7 +1875,7 @@ if __name__ == '__main__':
             check_for_DNS(newpaths.private_dir, paths.private_dir)
             # 22)
             if lastProvisionUSNs is not None:
-                update_provision_usn(ldbs.sam, minUSN, maxUSN)
+                update_provision_usn(ldbs.sam, minUSN, maxUSN, names.invocation)
             if opts.full and (names.policyid is None or names.policyid_dc is None):
                 update_policyids(names, ldbs.sam)
         if opts.full or opts.resetfileacl or opts.fixntacl:
index 0d39befc26622e8cac906ca05a53a6cd3a2e9219..7c9f223d11159f45fde04fa9c30675b3c86e1d6d 100644 (file)
@@ -322,7 +322,7 @@ def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf, lp)
         raise ProvisioningError("Unable to find uid/gid for Domain Admins rid")
     return names
 
-def update_provision_usn(samdb, low, high, replace=False):
+def update_provision_usn(samdb, low, high, id, replace=False):
     """Update the field provisionUSN in sam.ldb
 
     This field is used to track range of USN modified by provision and
@@ -333,6 +333,7 @@ def update_provision_usn(samdb, low, high, replace=False):
     :param samdb: An LDB object connect to sam.ldb
     :param low: The lowest USN modified by this upgrade
     :param high: The highest USN modified by this upgrade
+    :param id: The invocation id of the samba's dc
     :param replace: A boolean indicating if the range should replace any
                     existing one or appended (default)
     """
@@ -344,17 +345,24 @@ def update_provision_usn(samdb, low, high, replace=False):
                                 scope=ldb.SCOPE_SUBTREE,
                                 attrs=[LAST_PROVISION_USN_ATTRIBUTE, "dn"])
         for e in entry[0][LAST_PROVISION_USN_ATTRIBUTE]:
+            if not re.search(';', e):
+                e = "%s;%s" % (e, id)
             tab.append(str(e))
 
-    tab.append("%s-%s" % (low, high))
+    tab.append("%s-%s;%s" % (low, high, id))
     delta = ldb.Message()
     delta.dn = ldb.Dn(samdb, "@PROVISION")
     delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab,
         ldb.FLAG_MOD_REPLACE, LAST_PROVISION_USN_ATTRIBUTE)
+    entry = samdb.search(expression="(&(dn=@PROVISION)(provisionnerID=*))",
+                            base="", scope=ldb.SCOPE_SUBTREE,
+                            attrs=["provisionnerID"])
+    if len(entry) == 0 or len(entry[0]) == 0:
+        delta["provisionnerID"] = ldb.MessageElement(id, ldb.FLAG_MOD_ADD, "provisionnerID")
     samdb.modify(delta)
 
 
-def set_provision_usn(samdb, low, high):
+def set_provision_usn(samdb, low, high, id):
     """Set the field provisionUSN in sam.ldb
     This field is used to track range of USN modified by provision and
     upgradeprovision.
@@ -363,9 +371,12 @@ def set_provision_usn(samdb, low, high):
 
     :param samdb: An LDB object connect to sam.ldb
     :param low: The lowest USN modified by this upgrade
-    :param high: The highest USN modified by this upgrade"""
+    :param high: The highest USN modified by this upgrade
+    :param id: The invocationId of the provision"""
+
     tab = []
-    tab.append("%s-%s" % (low, high))
+    tab.append("%s-%s;%s" % (low, high, id))
+
     delta = ldb.Message()
     delta.dn = ldb.Dn(samdb, "@PROVISION")
     delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab,
@@ -390,25 +401,36 @@ def get_max_usn(samdb,basedn):
 
 
 def get_last_provision_usn(sam):
-    """Get the lastest USN modified by a provision or an upgradeprovision
+    """Get USNs ranges modified by a provision or an upgradeprovision
 
     :param sam: An LDB object pointing to the sam.ldb
-    :return: an integer corresponding to the highest USN modified by
-        (upgrade)provision, 0 is this value is unknown
+    :return: a dictionnary which keys are invocation id and values are an array
+             of integer representing the different ranges
     """
     entry = sam.search(expression="(&(dn=@PROVISION)(%s=*))" %
                         LAST_PROVISION_USN_ATTRIBUTE,
                         base="", scope=ldb.SCOPE_SUBTREE,
-                        attrs=[LAST_PROVISION_USN_ATTRIBUTE])
+                        attrs=[LAST_PROVISION_USN_ATTRIBUTE, "provisionnerID"])
     if len(entry):
-        range = []
-        idx = 0
+        myids = []
+        range = {}
         p = re.compile(r'-')
+        if entry[0].get("provisionnerID"):
+            for e in entry[0]["provisionnerID"]:
+                myids.append(str(e))
         for r in entry[0][LAST_PROVISION_USN_ATTRIBUTE]:
-            tab = p.split(str(r))
-            range.append(tab[0])
-            range.append(tab[1])
-            idx = idx + 1
+            tab1 = str(r).split(';')
+            if len(tab1) == 2:
+                id = tab1[1]
+            else:
+                id = "default"
+            if (len(myids) > 0 and id not in myids):
+                continue
+            tab2 = p.split(tab1[0])
+            if range.get(id) == None:
+                range[id] = []
+            range[id].append(tab2[0])
+            range[id].append(tab2[1])
         return range
     else:
         return None
@@ -1780,9 +1802,9 @@ def provision(logger, session_info, credentials, smbconf=None,
             lastProvisionUSNs = get_last_provision_usn(samdb)
             maxUSN = get_max_usn(samdb, str(names.rootdn))
             if lastProvisionUSNs is not None:
-                update_provision_usn(samdb, 0, maxUSN, 1)
+                update_provision_usn(samdb, 0, maxUSN, invocationid, 1)
             else:
-                set_provision_usn(samdb, 0, maxUSN)
+                set_provision_usn(samdb, 0, maxUSN, invocationid)
 
         create_krb5_conf(paths.krb5conf,
                          dnsdomain=names.dnsdomain, hostname=names.hostname,