Index: fedd/fedd_allocate_project.py
===================================================================
--- fedd/fedd_allocate_project.py	(revision 0ea11afb184736a45872959bc88e2cb71e328400)
+++ fedd/fedd_allocate_project.py	(revision 4ed10aefdf7652c7ea1c9a8488706ceb7c9436b8)
@@ -35,19 +35,25 @@
 fl.addHandler(nullHandler())
 
+
 class fedd_allocate_project_local:
     """
     Allocate projects on this machine in response to an access request.
     """
-    def __init__(self, dp=False, url=None, certs=None):
+    def __init__(self, config):
 	"""
 	Initializer.  Parses a configuration if one is given.
 	"""
 
-	self.dynamic_projects = dp
-	self.wap = '/usr/testbed/sbin/wap'
-	self.newproj = '/usr/testbed/sbin/newproj'
-	self.mkproj = '/usr/testbed/sbin/mkproj'
-	self.grantnodetype = '/usr/testbed/sbin/grantnodetype'
+	self.debug = config.get("access", "debug_project", False)
+	self.wap = config.get('access', 'wap', '/usr/testbed/sbin/wap')
+	self.newproj = config.get('access', 'newproj',
+		'/usr/testbed/sbin/newproj')
+	self.mkproj = config.get('access', 'mkproj', '/usr/testbed/sbin/mkproj')
+	self.addpubkey = config.get('access', 'addpubkey', 
+		'/usr/testbed/sbin/taddpubkey')
+	self.grantnodetype = config.get('access', 'grantnodetype', 
+		'/usr/testbed/sbin/grantnodetype')
 	self.log = logging.getLogger("fedd.allocate.local")
+	set_log_level(config, "access", self.log)
 
 	# Internal services are SOAP only
@@ -56,5 +62,9 @@
 		AllocateProjectRequestMessage.typecode,\
 		self.dynamic_project, AllocateProjectResponseMessage,\
-		"AllocateProjectResponseBody")\
+		"AllocateProjectResponseBody"), 
+		"StaticProject": make_soap_handler(\
+		StaticProjectRequestMessage.typecode,\
+		self.static_project, StaticProjectResponseMessage,\
+		"StaticProjectResponseBody")\
 		}
 	self.xmlrpc_services = { }
@@ -179,16 +189,14 @@
 	for cmd in cmds:
 	    self.log.debug("[dynamic_project]: %s" % ' '.join(cmd))
-	    if self.dynamic_projects:
+	    if not self.debug:
 		try:
 		    rc = subprocess.call(cmd)
 		except OSerror, e:
-		    raise fedd_proj.service_error(\
-			    fedd_proj.service_error.internal,
+		    raise service_error(service_error.internal,
 			    "Dynamic project subprocess creation error "+ \
 				    "[%s] (%s)" %  (cmd[1], e.strerror))
 
 	    if rc != 0: 
-		raise fedd_proj.service_error(\
-			fedd_proj.service_error.internal,
+		raise service_error(service_error.internal,
 			"Dynamic project subprocess error " +\
 				"[%s] (%d)" % (cmd[1], rc))
@@ -207,32 +215,78 @@
 	return rv
 
-
-class fedd_allocate_project_remote:
-    """
-    Allocate projects on a remote machine using the internal SOAP interface
-    """
-    def __init__(self, dp=False, url=None, certs=None):
-	"""
-	Initializer.  Parses a configuration if one is given.
-	"""
-
-	self.dynamic_projects = dp
-	self.url = url
-
-	if certs != None and isinstance(certs, type(tuple())):
-	    self.cert_file, self.trusted_certs, self.cert_pwd = certs
-	else:
-	    self.cert_file, self.trusted_certs, self.cert_pwd = \
-		    (None, None, None)
-	self.soap_services = { }
-	self.xmlrpc_services = { }
+    def static_project(self, req, fedid=None):
+	"""
+	Be certain that the local project in the request has access to the
+	proper resources and users have correct keys.  Add them if necessary.
+	"""
+
+	cmds =  []
+
+	# While we should be more careful about this, for the short term, add
+	# the keys to the specified users.
+
+	try:
+	    users = req['StaticProjectRequestBody']['project']['user']
+	    pname = req['StaticProjectRequestBody']['project']\
+		    ['name']['localname']
+	    resources = req['StaticProjectRequestBody'].get('resources', [])
+	except KeyError:
+	    raise service_error(service_error.req, "Badly formed request")
+
+
+	for u in users:
+	    try:
+		name = u['userID']['localname']
+	    except KeyError:
+		raise service_error(service_error.req, "Badly formed user")
+	    for sk in [ k['sshPubkey'] for k in u.get('access', []) \
+		    if k.has_key('sshPubkey')]:
+		cmds.append((self.addpubkey, '-w', '-u', name, '-k', sk))
 	
-    def dynamic_project(self, req, fedid=None):
+
+	# Add commands to grant access to any resources in the request.  The
+	# list comprehension pulls out the hardware types in the node entries
+	# in the resources list.
+	for nt in [ h for r in resources \
+		if r.has_key('node') and r['node'].has_key('hardware')\
+		    for h in r['node']['hardware'] ] :
+	    cmds.append((self.wap, self.grantnodetype, '-p', pname, nt))
+
+	# Run the commands 
+	rc = 0
+	for cmd in cmds:
+	    self.log.debug("[static_project]: %s" % ' '.join(cmd))
+	    if not self.debug:
+		try:
+		    rc = subprocess.call(cmd)
+		except OSError, e:
+		    print "Static project subprocess creation error "+ \
+				    "[%s] (%s)" %  (cmd[0], e.strerror)
+		    raise service_error(service_error.internal,
+			    "Static project subprocess creation error "+ \
+				    "[%s] (%s)" %  (cmd[0], e.strerror))
+
+	    if rc != 0: 
+		raise service_error(service_error.internal,
+			"Static project subprocess error " +\
+				"[%s] (%d)" % (cmd[0], rc))
+
+	return { 'project': req['StaticProjectRequestBody']['project']}
+
+def make_proxy(method, req_name, req_alloc, resp_name):
+    """
+    Construct the proxy calling function from the given parameters.
+    """
+
+    # Define the proxy, NB, the parameters to make_proxy are visible to the
+    # definition of proxy.
+    def proxy(self, req, fedid=None):
 	"""
 	Send req on to a remote project instantiator.
 
-	Req is just the projectAllocType object.  This function re-wraps it.
+	Req is just the message to be sent.  This function re-wraps it.
 	It also rethrows any faults.
 	"""
+
 	# No retry loop here.  Proxy servers must correctly authenticate
 	# themselves without help
@@ -249,23 +303,84 @@
 		transdict={ 'ssl_context' : ctx })
 
-	if req.has_key('AllocateProjectRequestBody'):
-	    req = req['AllocateProjectRequestBody']
+	if req.has_key(req_name):
+	    req = req[req_name]
 	else:
 	    raise service_error(service_error.req, "Bad formated request");
 
 	# Reconstruct the full request message
-	msg = AllocateProjectRequestMessage()
-	msg.set_element_AllocateProjectRequestBody(
-		pack_soap(msg, "AllocateProjectRequestBody", req))
+	msg = req_alloc()
+	set_elem = getattr(msg, "set_element_%s" % req_name)
+	set_elem(pack_soap(msg, req_name, req))
 	try:
-	    resp = port.AllocateProject(msg)
+	    mattr = getattr(port, method)
+	    resp = mattr(msg)
 	except ZSI.ParseException, e:
 	    raise service_error(service_error.proxy,
 		    "Bad format message (XMLRPC??): %s" % str(e))
+	except ZSI.FaultException, e:
+	    resp = e.fault.detail[0]
+
 	r = unpack_soap(resp)
 
-	if r.has_key('AllocateProjectResponseBody'):
-	    return r['AllocateProjectResponseBody']
+	if r.has_key(resp_name):
+	    return r[resp_name]
 	else:
 	    raise service_error(service_error.proxy, "Bad proxy response")
-
+    # NB: end of proxy function definition	
+    return proxy
+
+class fedd_allocate_project_remote:
+    """
+    Allocate projects on a remote machine using the internal SOAP interface
+    """
+    dynamic_project = make_proxy("AllocateProject",
+	    "AllocateProjectRequestBody", AllocateProjectRequestMessage,
+	    "AllocateProjectResponseBody")
+    static_project = make_proxy("StaticProject",
+	    "StaticProjectRequestBody", StaticProjectRequestMessage,
+	    "StaticProjectResponseBody")
+
+    def __init__(self, config):
+	"""
+	Initializer.  Parses a configuration if one is given.
+	"""
+
+	self.debug = config.get("access", "debug_project", False)
+	self.url = config.get("access", "dynamic_projects_url", "")
+
+	self.cert_file = config.get("access", "cert_file", None)
+	self.cert_pwd = config.get("access", "cert_pwd", None)
+	self.trusted_certs = config.get("access", "trusted_certs", None)
+
+	# Certs are promoted from the generic to the specific, so without a if
+	# no dynamic project certificates, then proxy certs are used, and if
+	# none of those the main certs.
+
+	if config.has_option("globals", "proxy_cert_file"):
+	    if not self.cert_file:
+		self.cert_file = config.get("globals", "proxy_cert_file")
+		if config.has_option("globals", "porxy_cert_pwd"):
+		    self.cert_pwd = config.get("globals", "proxy_cert_pwd")
+
+	if config.has_option("globals", "proxy_trusted_certs") and \
+		not self.trusted_certs:
+		self.trusted_certs = \
+			config.get("globals", "proxy_trusted_certs")
+
+	if config.has_option("globals", "cert_file"):
+	    has_pwd = config.has_option("globals", "cert_pwd")
+	    if not self.cert_file:
+		self.cert_file = config.get("globals", "cert_file")
+		if has_pwd: 
+		    self.cert_pwd = config.get("globals", "cert_pwd")
+
+	if config.get("globals", "trusted_certs") and not self.trusted_certs:
+		self.trusted_certs = \
+			config.get("globals", "trusted_certs")
+
+	self.soap_services = { }
+	self.xmlrpc_services = { }
+	self.log = logging.getLogger("fedd.allocate.remote")
+	set_log_level(config, "access", self.log)
+	#self.dynamic_project = fedd_allocate_project_remote.dynamic_project
+	#self.static_project = fedd_allocate_project_remote.static_project
