Index: fedd/federation/access.py
===================================================================
--- fedd/federation/access.py	(revision 2c1fd212f93f3a9979c48f0279f6c7694adb6787)
+++ fedd/federation/access.py	(revision 623a2c908699d0e995d4323ccfb0d343f3bcc519)
@@ -68,8 +68,7 @@
         self.state_lock = Lock()
 	self.state = { }
+	# subclasses fill with what and how they export.
+	self.exports = { }
 	# XXX: Configurable
-	self.exports = set(('SMB', 'seer', 'tmcd', 'userconfig', 
-	    'project_export', 'local_seer_control', 'seer_master', 
-	    'hide_hosts'))
 	self.imports = set(('SMB', 'seer', 'userconfig', 'seer_master',
 	    'hide_hosts'))
@@ -361,47 +360,51 @@
 
     def export_SMB(self, id, state, project, user, attrs):
-	return { 
-		'id': id,
-		'name': 'SMB',
-		'visibility': 'export',
-		'server': 'http://fs:139',
-		'fedAttr': [
-			{ 'attribute': 'SMBSHARE', 'value': 'USERS' },
-			{ 'attribute': 'SMBUSER', 'value': user },
-			{ 'attribute': 'SMBPROJ', 'value': project },
-		    ]
-		}
+	if project and user:
+	    return [{ 
+		    'id': id,
+		    'name': 'SMB',
+		    'visibility': 'export',
+		    'server': 'http://fs:139',
+		    'fedAttr': [
+			    { 'attribute': 'SMBSHARE', 'value': 'USERS' },
+			    { 'attribute': 'SMBUSER', 'value': user },
+			    { 'attribute': 'SMBPROJ', 'value': project },
+			]
+		    }]
+	else:
+	    self.log.warn("Cannot export SMB w/o user and project")
+	    return [ ]
 
     def export_seer(self, id, state, project, user, attrs):
-	return { 
+	return [{ 
 		'id': id,
 		'name': 'seer',
 		'visibility': 'export',
 		'server': 'http://control:16606',
-		}
+		}]
 
     def export_local_seer(self, id, state, project, user, attrs):
-	return { 
+	return [{ 
 		'id': id,
 		'name': 'local_seer_control',
 		'visibility': 'export',
 		'server': 'http://control:16606',
-		}
+		}]
 
     def export_seer_master(self, id, state, project, user, attrs):
-	return { 
+	return [{ 
 		'id': id,
 		'name': 'seer_master',
 		'visibility': 'export',
 		'server': 'http://seer-master:17707',
-		}
+		}]
 
     def export_tmcd(self, id, state, project, user, attrs):
-	return { 
+	return [{ 
 		'id': id,
 		'name': 'seer',
 		'visibility': 'export',
 		'server': 'http://boss:7777',
-		}
+		}]
 
     def export_userconfig(self, id, state, project, user, attrs):
@@ -410,5 +413,5 @@
 	    cid, cert = self.export_userconf(project)
 	    state['userconfig'] = unicode(cid)
-	    return {
+	    return [{
 		    'id': id,
 		    'name': 'userconfig',
@@ -418,10 +421,10 @@
 			{ 'attribute': 'cert', 'value': cert },
 		    ]
-		    }
+		    }]
 	else:
-	    return None
+	    return [ ]
 
     def export_hide_hosts(self, id, state, project, user, attrs):
-	return {
+	return [{
 		'id': id, 
 		'name': 'hide_hosts',
@@ -429,11 +432,15 @@
 		'fedAttr': [ x for x in attrs \
 			if x.get('attribute', "") == 'hosts'],
-		}
-
-    def export_services(self, sreq, project, user):
+		}]
+
+    def export_project_export(self, id, state, project, user, attrs):
+	rv = [ ]
+	rv.extend(self.export_SMB(id, state, project, user, attrs))
+	rv.extend(self.export_userconfig(id, state, project, user, attrs))
+	return rv
+
+    def export_services(self, sreq, project=None, user=None):
 	exp = [ ]
 	state = { }
-	# XXX: Filthy shortcut here using http: so urlparse will give the right
-	# answers.
 	for s in sreq:
 	    sname = s.get('name', '')
@@ -443,32 +450,7 @@
 		if sname in self.exports:
 		    id = s.get('id', 'no_id')
-		    if sname == 'SMB':
-			exp.append(self.export_SMB(id, state, project, user,
+		    exp.extend(self.exports[sname](id, state, project, user,
 			    sattrs))
-		    elif sname == 'seer':
-			exp.append(self.export_seer(id, state, project, user,
-			    sattrs))
-		    elif sname == 'tmcd':
-			exp.append(self.export_tmcd(id, state, project, user,
-			    sattrs))
-		    elif sname == 'userconfig':
-			exp.append(self.export_userconfig(id, state,
-			    project, user, sattrs))
-		    elif sname == 'project_export':
-			exp.append(self.export_SMB(id, state, project, user,
-			    sattrs))
-			#exp.append(self.export_seer(id, state, project, user,
-			#sattrs))
-			exp.append(self.export_userconfig(id, state,
-			    project, user, sattrs))
-		    elif sname == 'local_seer_control':
-			exp.append(self.export_local_seer(id, state, project,
-			    user, sattrs))
-		    elif sname == 'seer_master':
-			exp.append(self.export_seer_master(id, state, project,
-			    user, sattrs))
-		    elif sname == 'hide_hosts':
-			exp.append(self.export_hide_hosts(id, state, project,
-			    user, sattrs))
+
 	return (exp, state)
 
@@ -497,8 +479,6 @@
 		'value': self.dragon_endpoint})
 	if self.deter_internal:
-	    print 'adding internal'
 	    msg['fedAttr'].append({'attribute': 'deter_internal',
 		'value': self.deter_internal})
-	else: print "internal: %s" % self.deter_internal
 	#XXX: ??
 	if self.dragon_vlans:
@@ -689,4 +669,48 @@
 	    raise service_error(service_error.internal,
 		    "Cannot write client.conf: %s" %s)
+
+    def configure_userconf(self, services, tmpdir):
+	"""
+	If the userconf service was imported, collect the configuration data.
+	"""
+	for s in services:
+	    s_name = s.get('name', '')
+	    s_vis = s.get('visibility','')
+	    if s_name  == 'userconfig' and s_vis == 'import':
+		# Collect ther server and certificate info.
+		u = s.get('server', None)
+		for a in s.get('fedAttr', []):
+		    if a.get('attribute',"") == 'cert':
+			cert = a.get('value', None)
+			break
+		else:
+		    cert = None
+
+		if cert:
+		    # Make a temporary certificate file for get_url.  The
+		    # finally clause removes it whether something goes
+		    # wrong (including an exception from get_url) or not.
+		    try:
+			tfos, tn = tempfile.mkstemp(suffix=".pem")
+			tf = os.fdopen(tfos, 'w')
+			print >>tf, cert
+			tf.close()
+			self.log.debug("Getting userconf info: %s" % u)
+			get_url(u, tn, tmpdir, "userconf")
+			self.log.debug("Got userconf info: %s" % u)
+		    except EnvironmentError, e:
+			raise service_error(service.error.internal, 
+				"Cannot create temp file for " + 
+				"userconfig certificates: %s" % e)
+		    except:
+			t, v, st = sys.exc_info()
+			raise service_error(service_error.internal,
+				"Error retrieving %s: %s" % (u, v))
+		    finally:
+			if tn: os.remove(tn)
+		else:
+		    raise service_error(service_error.req,
+			    "No certificate for retreiving userconfig")
+		break
 
     def import_store_info(self, cf, connInfo):
@@ -737,2 +761,18 @@
 		    raise service_error(service_error.internal, 
 			'Bad Services missing info for import %s' % c)
+
+    def remove_dirs(self, dir):
+	"""
+	Remove the directory tree and all files rooted at dir.  Log any errors,
+	but continue.
+	"""
+	self.log.debug("[removedirs]: removing %s" % dir)
+	try:
+	    for path, dirs, files in os.walk(dir, topdown=False):
+		for f in files:
+		    os.remove(os.path.join(path, f))
+		for d in dirs:
+		    os.rmdir(os.path.join(path, d))
+	    os.rmdir(dir)
+	except EnvironmentError, e:
+	    self.log.error("Error deleting directory tree in %s" % e);
