[PATCH 5/7] upgradeprovision: Move to pythondoc format

Matthieu Patou mat at matws.net
Sun Feb 21 11:29:36 MST 2010


---
 source4/scripting/bin/upgradeprovision           |  195 +++++++++++++++++++---
 source4/scripting/python/samba/upgradehelpers.py |   42 ++++-
 2 files changed, 205 insertions(+), 32 deletions(-)

diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision
index 3ce6ae4..ac9ab64 100755
--- a/source4/scripting/bin/upgradeprovision
+++ b/source4/scripting/bin/upgradeprovision
@@ -68,6 +68,8 @@ GUESS = 	0x04
 PROVISION =	0x08
 CHANGEALL =	0xff
 
+__docformat__ = "restructuredText"
+
 # Attributes that are never copied from the reference provision (even if they
 # do not exist in the destination object).
 # This is most probably because they are populated automatcally when object is
@@ -127,12 +129,17 @@ opts = parser.parse_args()[0]
 whatToLog = define_what_to_log(opts)
 
 def messageprovision(text):
-	"""print a message if quiet is not set."""
+	"""Print a message if quiet is not set
+
+	:param text: Message to print """
 	if opts.debugprovision or opts.debugall:
 		print text
 
 def message(what,text):
-	"""print a message if quiet is not set."""
+	"""Print a message if this message type has been selected to be printed
+
+	:param what: Category of the message
+	:param text: Message to print """
 	if (whatToLog & what) or (what <= 0 ):
 		print text
 
@@ -145,35 +152,57 @@ creds = credopts.get_credentials(lp)
 creds.set_kerberos_state(DONT_USE_KERBEROS)
 setup_dir = opts.setupdir
 if setup_dir is None:
-    setup_dir = find_setup_dir()
+	setup_dir = find_setup_dir()
 
 session = system_session()
 
-# simple helper to allow back and forth rename
 def identic_rename(ldbobj,dn):
+	"""Perform a back and forth rename to trigger renaming on attribute that can't be directly modified.
+
+	:param lbdobj: An Ldb Object
+	:param dn: DN of the object to manipulate """
 	(before,sep,after)=str(dn).partition('=')
 	ldbobj.rename(dn,Dn(ldbobj,"%s=foo%s"%(before,after)))
 	ldbobj.rename(Dn(ldbobj,"%s=foo%s"%(before,after)),dn)
 
-# Create an array of backlinked attributes
 def populate_backlink(newpaths,creds,session,schemadn):
+	"""Populate an array with all the back linked attributes
+
+	This attributes that are modified automaticaly when
+	front attibutes are changed
+
+	:param newpaths: a list of paths for different provision objects
+	:param creds: credential for the authentification
+	:param session: session for connexion
+	:param schemadn: DN of the schema for the partition"""
 	newsam_ldb = Ldb(newpaths.samdb, session_info=session, credentials=creds,lp=lp)
 	linkedAttHash = get_linked_attributes(Dn(newsam_ldb,str(schemadn)),newsam_ldb)
 	backlinked.extend(linkedAttHash.values())
 
 # Create an array of  attributes with a dn synthax (2.5.5.1)
 def populate_dnsyntax(newpaths,creds,session,schemadn):
+	"""Populate an array with all the attributes that have DN synthax (oid 2.5.5.1)
+
+	:param newpaths: a list of paths for different provision objects
+	:param creds: credential for the authentification
+	:param session: session for connexion
+	:param schemadn: DN of the schema for the partition"""
 	newsam_ldb = Ldb(newpaths.samdb, session_info=session, credentials=creds,lp=lp)
 	res = newsam_ldb.search(expression="(attributeSyntax=2.5.5.1)",base=Dn(newsam_ldb,str(schemadn)),
 							scope=SCOPE_SUBTREE, attrs=["lDAPDisplayName"])
 	for elem in res:
 		dn_syntax_att.append(elem["lDAPDisplayName"])
 
-
-
 def sanitychecks(credentials,session_info,names,paths):
+	"""Populate an array with all the attributes that have DN synthax (oid 2.5.5.1)
+
+	:param creds: credential for the authentification
+	:param session_info: session for connexion
+	:param names: list of key provision parameters
+	:param paths: list of path to provision object
+	:return: Status of check (1 for Ok, 0 for not Ok) """
 	sam_ldb = Ldb(paths.samdb, session_info=session, credentials=creds,lp=lp,options=["modules:samba_dsdb"])
-	# First update the SD for the rootdn
+
 	sam_ldb.set_session_info(session)
 	res = sam_ldb.search(expression="objectClass=ntdsdsa",base=str(names.configdn),
 						 scope=SCOPE_SUBTREE,attrs=["dn"],controls=["search_options:1:2"])
@@ -188,8 +217,10 @@ domain with more than one DC, please demote the other(s) DC(s) before upgrading"
 		return 1
 
 
-# Debug a little bit
 def print_provision_key_parameters(names):
+	"""Do a a pretty print of provision parameters
+
+	:param names: list of key provision parameters """
 	message(GUESS, "rootdn      :"+str(names.rootdn))
 	message(GUESS, "configdn    :"+str(names.configdn))
 	message(GUESS, "schemadn    :"+str(names.schemadn))
@@ -208,9 +239,18 @@ def print_provision_key_parameters(names):
 	message(GUESS, "ntdsguid    :"+names.ntdsguid)
 	message(GUESS, "domainlevel :"+str(names.domainlevel))
 
-# Check for security descriptors modifications return 1 if it is and 0 otherwise
-# it also populate hash structure for later use in the upgrade process
 def handle_security_desc(ischema, att, msgElt, hashallSD, old, new):
+	"""Check if the security descriptor has been modified.
+
+	This function also populate a hash used for the upgrade process.
+	:param ischema: Boolean that indicate if it's the schema that is updated
+	:param att: Name of the attribute
+	:param msgElt: MessageElement object
+	:param hashallSD: Hash table with DN as key and the old SD as value
+	:param old: The updated LDAP object
+	:param new: The reference LDAP object
+	:return: 1 to indicate that the attribute should be kept, 0 for discarding it
+	"""
 	if ischema == 1 and att == "defaultSecurityDescriptor"  and msgElt.flags() == FLAG_MOD_REPLACE:
 		hashSD = {}
 		hashSD["oldSD"] = old[0][att]
@@ -226,11 +266,16 @@ def handle_security_desc(ischema, att, msgElt, hashallSD, old, new):
 		return 0
 	return 0
 
-# Handle special cases ... That's when we want to update a particular attribute
-# only, e.g. if it has a certain value or if it's for a certain object or
-# a class of object.
-# It can be also if we want to do a merge of value instead of a simple replace
 def handle_special_case(att, delta, new, old, ischema):
+	"""Define more complicate update rules for some attributes
+
+	:param att: The attribute to be updated
+	:param delta: A messageElement object that correspond to the difference between the updated object and the reference one
+	:param new: The reference object
+	:param old: The Updated object
+	:param ischema: A boolean that indicate that the attribute is part of a schema object
+	:return: 1 to indicate that the attribute should be kept, 0 for discarding it
+	"""
 	flag = delta.get(att).flags()
 	if (att == "gPLink" or att == "gPCFileSysPath") and \
 		flag ==  FLAG_MOD_REPLACE and str(new[0].dn).lower() == str(old[0].dn).lower():
@@ -277,6 +322,13 @@ def handle_special_case(att, delta, new, old, ischema):
 	return 0
 
 def update_secrets(newpaths, paths, creds, session):
+	"""Update secrets.ldb
+
+	:param newpaths: a list of paths for different provision objects from the reference provision
+	:param paths: a list of paths for different provision objects from the upgraded provision
+	:param creds: credential for the authentification
+	:param session: session for connexion"""
+
 	message(SIMPLE,"update secrets.ldb")
 	newsecrets_ldb = Ldb(newpaths.secrets, session_info=session, credentials=creds,lp=lp)
 	secrets_ldb = Ldb(paths.secrets, session_info=session, credentials=creds,lp=lp, options=["modules:samba_secrets"])
@@ -309,6 +361,7 @@ def update_secrets(newpaths, paths, creds, session):
 			listMissing.append(hash_new[k])
 		else:
 			listPresent.append(hash_new[k])
+
 	for entry in listMissing:
 		reference = newsecrets_ldb.search(expression="dn=%s"%entry,base="", scope=SCOPE_SUBTREE)
 		current = secrets_ldb.search(expression="dn=%s"%entry,base="", scope=SCOPE_SUBTREE)
@@ -353,6 +406,14 @@ def update_secrets(newpaths, paths, creds, session):
 		secrets_ldb.modify(delta)
 
 def dump_denied_change(dn,att,flagtxt,current,reference):
+	"""Print detailed information about why a changed is denied
+
+	:param dn: DN of the object which attribute is denied
+	:param att: Attribute that was supposed to be upgraded
+	:param flagtxt: Type of the update that should be performed (add, change, remove, ...)
+	:param current: Value(s) of the current attribute
+	:param reference: Value(s) of the reference attribute"""
+
 	message(CHANGE, "dn= "+str(dn)+" "+att+" with flag "+flagtxt+" is not allowed to be changed/removed, I discard this change ...")
 	if att != "objectSid" :
 		i = 0
@@ -368,9 +429,13 @@ def dump_denied_change(dn,att,flagtxt,current,reference):
 		message(CHANGE,"old : %s"%str(ndr_unpack( security.dom_sid,current[0])))
 		message(CHANGE,"new : %s"%str(ndr_unpack( security.dom_sid,reference[0])))
 
-#This function is for doing case by case treatment on special object
-
 def handle_special_add(sam_ldb,dn,names):
+	"""Handle special operation (like remove) on some object needed during upgrade
+
+	This is mostly due to wrong creation of the object in previous provision.
+	:param sam_ldb: An Ldb object representing the SAM database
+	:param dn: DN of the object to inspect
+	:param names: list of key provision parameters"""
 	dntoremove=None
 	if str(dn).lower() == ("CN=Certificate Service DCOM Access,CN=Builtin,%s"%names.rootdn).lower():
 		#This entry was misplaced lets remove it if it exists
@@ -395,6 +460,16 @@ def handle_special_add(sam_ldb,dn,names):
 #First dn to be created has the creation order 0, second has 1, ...
 #Index contain the current creation order
 def check_dn_nottobecreated(hash,index,listdn):
+	"""Check if one of the DN present in the list has a creation order greater than the current.
+
+	Hash is indexed by dn to be created, with each key is associated the creation order
+	First dn to be created has the creation order 0, second has 1, ...
+	Index contain the current creation order
+	:param hash: Hash holding the different DN of the object to be created as key
+	:param index: Current creation order
+	:param listdn: List of DNs on which the current DN depends on
+	:return: None if the current object do not depend on other object or if all object have been
+	created before."""
 	if listdn == None:
 		return None
 	for dn in listdn:
@@ -403,9 +478,18 @@ def check_dn_nottobecreated(hash,index,listdn):
 			return str(dn)
 	return None
 
-#This function tries to add the missing object "dn" if this object depends on some others
-# the function returns 0, if the object was created 1 is returned
 def add_missing_object(newsam_ldb, sam_ldb, dn, names, basedn, hash, index):
+	"""Add a new object if the dependencies are satisfied
+
+	The function add the object if the object on which it depends are already created
+	:param newsam_ldb: Ldb object representing the SAM db of the reference provision
+	:param sam_ldb: Ldb object representing the SAM db of the upgraded provision
+	:param dn: DN of the object to be added
+	:param names: List of key provision parameters
+	:param basedn: DN of the partition to be updated
+	:param hash: Hash holding the different DN of the object to be created as key
+	:param index: Current creation order
+	:return: 1 if the object was created 0 otherwise"""
 	handle_special_add(sam_ldb,dn,names)
 	reference = newsam_ldb.search(expression="dn=%s"%(str(dn)),base=basedn,
 					scope=SCOPE_SUBTREE,controls=["search_options:1:2"])
@@ -428,12 +512,25 @@ def add_missing_object(newsam_ldb, sam_ldb, dn, names, basedn, hash, index):
 	return 1
 
 def gen_dn_index_hash(listMissing):
+	"""Generate a hash associating the DN to its creation order
+
+	:param listMissing: List of DN
+	:return: Hash with DN as keys and creation order as values"""
 	hash = {}
 	for i in range(0,len(listMissing)):
 		hash[str(listMissing[i]).lower()] = i
 	return hash
 
 def add_missing_entries(newsam_ldb, sam_ldb, names, basedn,list):
+	"""Add the missing object whose DN is the list
+
+	The function add the object if the object on which it depends are already created
+	:param newsam_ldb: Ldb object representing the SAM db of the reference provision
+	:param sam_ldb: Ldb object representing the SAM db of the upgraded provision
+	:param dn: DN of the object to be added
+	:param names: List of key provision parameters
+	:param basedn: DN of the partition to be updated
+	:param list: List of DN to be added in the upgraded provision"""
 	listMissing = []
 	listDefered = list
 
@@ -459,6 +556,19 @@ def add_missing_entries(newsam_ldb, sam_ldb, names, basedn,list):
 # the scan is done in cross partition mode.
 # If "ischema" is true, then special handling is done for dealing with schema
 def check_diff_name(newpaths, paths, creds, session, basedn, names, ischema):
+	"""Check differences between the reference provision and the upgraded one.
+
+	This function will also add the missing object and update existing object to add
+	or remove attributes that were missing.
+	:param newpaths: List of paths for different provision objects from the reference provision
+	:param paths: List of paths for different provision objects from the upgraded provision
+	:param creds: Credential for the authentification
+	:param session: Session for connexion
+	:param basedn: DN of the partition to update
+	:param names: List of key provision parameters
+	:param ischema: Boolean indicating if the update is about the schema only
+	:return: Hash of security descriptor to update"""
+
 	hash_new = {}
 	hash = {}
 	hashallSD = {}
@@ -573,8 +683,15 @@ def check_diff_name(newpaths, paths, creds, session, basedn, names, ischema):
 	message(SIMPLE,"There are %d changed objects"%(changed))
 	return hashallSD
 
-# Check that SD are correct
 def check_updated_sd(newpaths, paths, creds, session, names):
+	"""Check if the security descriptor in the upgraded provision are the same as the reference
+
+	:param newpaths: List of paths for different provision objects from the reference provision
+	:param paths: List of paths for different provision objects from the upgraded provision
+	:param creds: Credential for the authentification
+	:param session: Session for connexion
+	:param basedn: DN of the partition to update
+	:param names: List of key provision parameters"""
 	newsam_ldb = Ldb(newpaths.samdb, session_info=session, credentials=creds,lp=lp)
 	sam_ldb = Ldb(paths.samdb, session_info=session, credentials=creds,lp=lp)
 	reference = newsam_ldb.search(expression="objectClass=*",base=str(names.rootdn), scope=SCOPE_SUBTREE,attrs=["dn","nTSecurityDescriptor"],controls=["search_options:1:2"])
@@ -591,10 +708,18 @@ def check_updated_sd(newpaths, paths, creds, session, names):
 				print "%s new sddl/sddl in ref"%key
 				print "%s\n%s"%(sddl,hash_new[key])
 
-# Simple update method for updating the SD that rely on the fact that nobody
-# should have modified the SD
-# This assumption is safe right now (alpha9) but should be removed asap
 def update_sd(paths, creds, session, names):
+	"""Update security descriptor of the current provision
+
+	During the different pre release of samba4 security descriptors (SD) were notarly broken (up to alpha11 included)
+	This function allow to get them back in order, this function make the assumption that nobody has modified manualy an SD
+	and so SD can be safely recalculated from scratch to get them right.
+
+	:param paths: List of paths for different provision objects from the upgraded provision
+	:param creds: Credential for the authentification
+	:param session: Session for connexion
+	:param names: List of key provision parameters"""
+
 	sam_ldb = Ldb(paths.samdb, session_info=session, credentials=creds,lp=lp,options=["modules:samba_dsdb"])
 	sam_ldb.transaction_start()
 	# First update the SD for the rootdn
@@ -649,6 +774,12 @@ def update_sd(paths, creds, session, names):
 
 
 def update_basesamdb(newpaths, paths, names):
+	"""Update the provision container db: sam.ldb
+
+	:param newpaths: List of paths for different provision objects from the reference provision
+	:param paths: List of paths for different provision objects from the upgraded provision
+	:param names: List of key provision parameters"""
+
 	message(SIMPLE,"Copy samdb")
 	shutil.copy(newpaths.samdb,paths.samdb)
 
@@ -672,11 +803,22 @@ def update_basesamdb(newpaths, paths, names):
 		os.remove(configldb)
 
 def update_privilege(newpaths, paths):
+	"""Update the privilege database
+
+	:param newpaths: List of paths for different provision objects from the reference provision
+	:param paths: List of paths for different provision objects from the upgraded provision"""
 	message(SIMPLE,"Copy privilege")
 	shutil.copy(os.path.join(newpaths.private_dir,"privilege.ldb"),os.path.join(paths.private_dir,"privilege.ldb"))
 
 # For each partition check the differences
 def update_samdb(newpaths, paths, creds, session, names):
+	"""Upgrade the SAM DB contents for all the provision
+
+	:param newpaths: List of paths for different provision objects from the reference provision
+	:param paths: List of paths for different provision objects from the upgraded provision
+	:param creds: Credential for the authentification
+	:param session: Session for connexion
+	:param names: List of key provision parameters"""
 
 	message(SIMPLE, "Doing schema update")
 	hashdef = check_diff_name(newpaths,paths,creds,session,str(names.schemadn),names,1)
@@ -686,6 +828,13 @@ def update_samdb(newpaths, paths, creds, session, names):
 	message(SIMPLE,"Done with scanning")
 
 def update_machine_account_password(paths, creds, session, names):
+	"""Update (change) the password of the current DC both in the SAM db and in secret one
+
+	:param paths: List of paths for different provision objects from the upgraded provision
+	:param creds: Credential for the authentification
+	:param session: Session for connexion
+	:param names: List of key provision parameters"""
+
 	secrets_ldb = Ldb(paths.secrets, session_info=session, credentials=creds,lp=lp)
 	secrets_ldb.transaction_start()
 	secrets_msg = secrets_ldb.search(expression=("samAccountName=%s$" % names.netbiosname), attrs=["secureChannelType"])
diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py
index f456060..190a8f7 100755
--- a/source4/scripting/python/samba/upgradehelpers.py
+++ b/source4/scripting/python/samba/upgradehelpers.py
@@ -26,7 +26,6 @@ import os
 import sys
 import string
 import re
-# Find right directory when running from source tree
 
 import samba
 from samba import Ldb, DS_DOMAIN_FUNCTION_2000
@@ -37,8 +36,13 @@ from samba.provisionexceptions import ProvisioningError
 from samba.dcerpc import misc, security
 from samba.ndr import ndr_pack, ndr_unpack
 
-# Get Paths for important objects (ldb, keytabs ...)
 def get_paths(param,targetdir=None,smbconf=None):
+	"""Get paths to important provision objects (smb.conf, ldb files, ...)
+
+	:param param: Param object
+	:param targetdir: Directory where the provision is (or will be) stored
+	:param smbconf: Path to the smb.conf file
+	:return: A list with the path of important provision objects"""
 	if targetdir is not None:
 		if (not os.path.exists(os.path.join(targetdir, "etc"))):
 			os.makedirs(os.path.join(targetdir, "etc"))
@@ -55,10 +59,16 @@ def get_paths(param,targetdir=None,smbconf=None):
 	return paths
 
 
-# This function guesses (fetches) informations needed to make a fresh provision
-# from the current provision
-# It includes: realm, workgroup, partitions, netbiosname, domain guid, ...
 def find_provision_key_parameters(param,credentials,session_info,paths,smbconf):
+	"""Get key provision parameters (realm, domain, ...) from a given provision
+
+	:param param: Param object
+	:param credentials: Credentials for the authentification
+	:param session_info: Session object
+	:param paths: A list of path to provision object
+	:param smbconf: Path to the smb.conf file
+	:return: A list of key provision parameters"""
+
 	lp = param.LoadParm()
 	lp.load(paths.smbconf)
 	names = ProvisionNames()
@@ -145,6 +155,15 @@ def find_provision_key_parameters(param,credentials,session_info,paths,smbconf):
 # This provision will be the reference for knowing what has changed in the
 # since the latest upgrade in the current provision
 def newprovision(names,setup_dir,creds,session,smbconf,provdir,messagefunc):
+	"""Create a new provision
+
+	:param names: List of provision parameters
+	:param setup_dis: Directory where the setup files are stored
+	:param creds: Credentials for the authentification
+	:param session: Session object
+	:param smbconf: Path to the smb.conf file
+	:param provdir: Directory where the provision will be stored
+	:param messagefunc: A function for displaying the message of the provision"""
 	if os.path.isdir(provdir):
 		rmall(provdir)
 	logstd=os.path.join(provdir,"log.std")
@@ -176,11 +195,13 @@ def newprovision(names,setup_dir,creds,session,smbconf,provdir,messagefunc):
 		dom_for_fun_level=names.domainlevel,
 		ldap_dryrun_mode=None,useeadb=True)
 
-# This function sorts two DNs in the lexicographical order and put higher level
-# DN before.
-# So given the dns cn=bar,cn=foo and cn=foo the later will be return as smaller
-# (-1) as it has less level
 def dn_sort(x,y):
+	"""Sorts two DNs in the lexicographical order it and put higher level DN before.
+
+	So given the dns cn=bar,cn=foo and cn=foo the later will be return as smaller
+	:param x: First object to compare
+	:param y: Second object to compare
+	"""
 	p = re.compile(r'(?<!\\),')
 	tab1 = p.split(str(x))
 	tab2 = p.split(str(y))
@@ -210,6 +231,9 @@ def dn_sort(x,y):
 
 
 def rmall(topdir):
+	"""Remove a directory its contents and all its subdirectory
+
+	:param topdir: Directory to remove"""
 	for root, dirs, files in os.walk(topdir, topdown=False):
 		for name in files:
 			os.remove(os.path.join(root, name))
-- 
1.6.3.3


--------------040502050402080101070707
Content-Type: text/x-patch;
 name="0001-upgradeprovision-split-the-big-script-to-put-reusabl.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename*0="0001-upgradeprovision-split-the-big-script-to-put-reusabl.pa";
 filename*1="tch"



More information about the samba-technical mailing list