[patches] upgradeprovision

Jelmer Vernooij jelmer at samba.org
Sun Jan 31 14:00:00 MST 2010


Hi Matthieu,

Some initial review comments:

On Sun, Jan 31, 2010 at 11:36:14PM +0300, Matthieu Patou wrote:
> diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision
> index e2ee8d0..2c06007 100755
> --- a/source4/scripting/bin/upgradeprovision
> +++ b/source4/scripting/bin/upgradeprovision
> @@ -30,16 +30,16 @@ import random
>  import string
>  import re
>  import base64
> +from base64 import b64encode
^^^ Please either import what you need from the module or use
MODULE.THING everywhere.

>  import tempfile
>  # Find right directory when running from source tree
>  sys.path.insert(0, "bin/python")
>  
> -from base64 import b64encode
>  
>  import samba
>  from samba.credentials import DONT_USE_KERBEROS
>  from samba.auth import system_session, admin_session
> -from samba import Ldb, DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008, DS_DC_FUNCTION_2008_R2
> +from samba import Ldb 
>  from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
>  import ldb
>  import samba.getopt as options
> @@ -47,12 +47,13 @@ from samba.samdb import SamDB
>  from samba import param
>  from samba import glue
>  from samba.misc import messageEltFlagToString
> -from samba.provision import  ProvisionNames,provision_paths_from_lp,find_setup_dir,FILL_FULL,provision, get_domain_descriptor, get_config_descriptor, secretsdb_self_join
> +from samba.provision import  find_setup_dir, get_domain_descriptor, get_config_descriptor, secretsdb_self_join
>  from samba.provisionexceptions import ProvisioningError
>  from samba.schema import get_dnsyntax_attributes, get_linked_attributes, Schema, get_schema_descriptor
>  from samba.dcerpc import misc, security
>  from samba.ndr import ndr_pack, ndr_unpack
>  from samba.dcerpc.misc import SEC_CHAN_BDC
> +from samba.upgradehelpers import dn_sort,get_paths,newprovision,find_provision_key_parameters,rmall
^^ Please use ", " rather than just ","

> @@ -899,24 +716,27 @@ def update_machine_account_password(paths,creds,session,names):
>  	else:
>  		secrets_ldb.transaction_cancel()
>  
> +def setup_path(file):
> +	return os.path.join(setup_dir, file)
>  # From here start the big steps of the program
>  # First get files paths
> -paths=get_paths(smbconf=smbconf)
> +paths=get_paths(param,smbconf=smbconf)
^^^ Similarly, please use more space here

> diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py
> new file mode 100755
> index 0000000..58da4db
> --- /dev/null
> +++ b/source4/scripting/python/samba/upgradehelpers.py
...
> +import os
> +import sys
> +import string
> +import re
> +# Find right directory when running from source tree
^^^ This comment doesn't seem true anymore
> +
> +import samba
> +from samba import Ldb, DS_DOMAIN_FUNCTION_2000
> +from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
> +import ldb
> +from samba.provision import  ProvisionNames,provision_paths_from_lp,FILL_FULL,provision
> +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):
> +	if targetdir is not None:
> +		if (not os.path.exists(os.path.join(targetdir, "etc"))):
> +			os.makedirs(os.path.join(targetdir, "etc"))
> +		smbconf = os.path.join(targetdir, "etc", "smb.conf")
> +	if smbconf is None:
> +			smbconf = param.default_path()
> +
> +	if not os.path.exists(smbconf):
> +		raise ProvisioningError("Unable to find smb.conf ...")
> +
> +	lp = param.LoadParm()
> +	lp.load(smbconf)
> +	paths = provision_paths_from_lp(lp,lp.get("realm"))
> +	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):
> +	lp = param.LoadParm()
> +	lp.load(paths.smbconf)
> +	names = ProvisionNames()
> +	# NT domain, kerberos realm, root dn, domain dn, domain dns name
> +	names.domain = string.upper(lp.get("workgroup"))
> +	names.realm = lp.get("realm")
> +	basedn = "DC=" + names.realm.replace(".",",DC=")
> +	names.dnsdomain = names.realm
> +	names.realm = string.upper(names.realm)
> +	# netbiosname
> +	secrets_ldb = Ldb(paths.secrets, session_info=session_info, credentials=credentials,lp=lp, options=["modules:samba_secrets"])
> +	# Get the netbiosname first (could be obtained from smb.conf in theory)
> +	attrs = ["sAMAccountName"]
> +	res = secrets_ldb.search(expression="(flatname=%s)"%names.domain,base="CN=Primary Domains", scope=SCOPE_SUBTREE, attrs=attrs)
> +	names.netbiosname = str(res[0]["sAMAccountName"]).replace("$","")
> +
> +	names.smbconf = smbconf
> +	# It's important here to let ldb load with the old module or it's quite
> +	# certain that the LDB won't load ...
> +	samdb = Ldb(paths.samdb, session_info=session_info,
> +		    credentials=credentials, lp=lp, options=["modules:samba_dsdb"])
> +
> +	# That's a bit simplistic but it's ok as long as we have only 3
> +	# partitions
> +	attrs2 = ["defaultNamingContext", "schemaNamingContext","configurationNamingContext","rootDomainNamingContext"]
> +	current = samdb.search(expression="(objectClass=*)",base="", scope=SCOPE_BASE, attrs=attrs2)
> +
> +	names.configdn = current[0]["configurationNamingContext"]
> +	configdn = str(names.configdn)
> +	names.schemadn = current[0]["schemaNamingContext"]
> +	if not (ldb.Dn(samdb, basedn) == (ldb.Dn(samdb, current[0]["defaultNamingContext"][0]))):
> +		raise ProvisioningError(("basedn in %s (%s) and from %s (%s) is not the same ..." % (paths.samdb, str(current[0]["defaultNamingContext"][0]), paths.smbconf, basedn)))
> +
> +	names.domaindn=current[0]["defaultNamingContext"]
> +	names.rootdn=current[0]["rootDomainNamingContext"]
> +	# default site name
> +	attrs3 = ["cn"]
> +	res3= samdb.search(expression="(objectClass=*)",base="CN=Sites,"+configdn, scope=SCOPE_ONELEVEL, attrs=attrs3)
> +	names.sitename = str(res3[0]["cn"])
> +
> +	# dns hostname and server dn
> +	attrs4 = ["dNSHostName"]
> +	res4= samdb.search(expression="(CN=%s)"%names.netbiosname,base="OU=Domain Controllers,"+basedn, \
> +						scope=SCOPE_ONELEVEL, attrs=attrs4)
> +	names.hostname = str(res4[0]["dNSHostName"]).replace("."+names.dnsdomain,"")
> +
> +	server_res = samdb.search(expression="serverReference=%s"%res4[0].dn, attrs=[], base=configdn)
> +	names.serverdn = server_res[0].dn
> +
> +	# invocation id/objectguid
> +	res5 = samdb.search(expression="(objectClass=*)",base="CN=NTDS Settings,%s" % str(names.serverdn), scope=SCOPE_BASE, attrs=["invocationID","objectGUID"])
> +	names.invocation = str(ndr_unpack( misc.GUID,res5[0]["invocationId"][0]))
> +	names.ntdsguid = str(ndr_unpack( misc.GUID,res5[0]["objectGUID"][0]))
> +
> +	# domain guid/sid
> +	attrs6 = ["objectGUID", "objectSid","msDS-Behavior-Version" ]
> +	res6 = samdb.search(expression="(objectClass=*)",base=basedn, scope=SCOPE_BASE, attrs=attrs6)
> +	names.domainguid = str(ndr_unpack( misc.GUID,res6[0]["objectGUID"][0]))
> +	names.domainsid = ndr_unpack( security.dom_sid,res6[0]["objectSid"][0])
> +	if res6[0].get("msDS-Behavior-Version") == None or int(res6[0]["msDS-Behavior-Version"][0]) < DS_DOMAIN_FUNCTION_2000:
> +		names.domainlevel = DS_DOMAIN_FUNCTION_2000
> +	else:
> +		names.domainlevel = int(res6[0]["msDS-Behavior-Version"][0])
> +
> +	# policy guid
> +	attrs7 = ["cn","displayName"]
> +	res7 = samdb.search(expression="(displayName=Default Domain Policy)",base="CN=Policies,CN=System,"+basedn, \
> +							scope=SCOPE_ONELEVEL, attrs=attrs7)
> +	names.policyid = str(res7[0]["cn"]).replace("{","").replace("}","")
> +	# dc policy guid
> +	attrs8 = ["cn","displayName"]
> +	res8 = samdb.search(expression="(displayName=Default Domain Controllers Policy)",base="CN=Policies,CN=System,"+basedn, \
> +							scope=SCOPE_ONELEVEL, attrs=attrs7)
> +	if len(res8) == 1:
> +		names.policyid_dc = str(res8[0]["cn"]).replace("{","").replace("}","")
> +	else:
> +		names.policyid_dc = None
> +
> +	return names
> +
> +
> +# Create a fresh new reference provision
> +# 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):
> +	if os.path.isdir(provdir):
> +		rmall(provdir)
> +	logstd=os.path.join(provdir,"log.std")
> +	os.chdir(os.path.join(setup_dir,".."))
> +	os.mkdir(provdir)
> +	os.close(2)
> +	sys.stderr = open("%s/provision.log"%provdir, "w")
^^^ please don't do this sort of stuff. instead, pass in a function that 
	can be used for printing debug output or a file handle that should
	be used for loggin.

> +# 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
^^^ You should be able to use sort() with dn's, since we expose
	ldb_dn_cmp() at the Python level. Have you tried that?

> +def dn_sort(x,y):
> +	p = re.compile(r'(?<!\\),')
> +	tab1 = p.split(str(x))
> +	tab2 = p.split(str(y))
> +	min = 0
> +	if (len(tab1) > len(tab2)):
> +		min = len(tab2)
> +	elif (len(tab1) < len(tab2)):
> +		min = len(tab1)
> +	else:
> +		min = len(tab1)
> +	len1=len(tab1)-1
> +	len2=len(tab2)-1
> +	space = " "
> +	# Note: python range go up to upper limit but do not include it
> +	for i in range(0,min):
> +		ret=cmp(tab1[len1-i],tab2[len2-i])
> +		if(ret != 0):
> +			return ret
> +		else:
> +			if(i==min-1):
> +				assert len1!=len2,"PB PB PB"+space.join(tab1)+" / "+space.join(tab2)
> +				if(len1>len2):
> +					return 1
> +				else:
> +					return -1
> +	return ret
> +

Cheers,

Jelmer

- 


More information about the samba-technical mailing list